]> gitweb.factorcode.org Git - factor.git/blob - basis/http/server/requests/requests-tests.factor
afb3eb7b16c9073cef46155af11258c0929bacdf
[factor.git] / basis / http / server / requests / requests-tests.factor
1 USING: accessors assocs continuations http http.client http.client.private
2 http.server http.server.requests io.streams.limited io.streams.string kernel
3 math math.parser multiline namespaces peg sequences splitting tools.test urls ;
4 IN: http.server.requests.tests
5
6 : normalize-nl ( str -- str' )
7     "\n" "\r\n" replace ;
8
9 : request>string ( request -- string )
10     [ write-request ] with-string-writer ;
11
12 : string>request ( str -- request )
13     [ request-limit get limited-input read-request ] with-string-reader ;
14
15 ! POST requests
16 { "foo=bar" "7" } [
17     "foo=bar" "localhost" <post-request> request>string string>request
18     [ post-data>> data>> ] [ header>> "content-length" of ] bi
19 ] unit-test
20
21 { f "0" } [
22     "" "localhost" <post-request> request>string string>request
23     [ post-data>> data>> ] [ header>> "content-length" of ] bi
24 ] unit-test
25
26 ! Incorrect content-length works fine
27 { H{ { "foo" "bar" } } } [
28     { { "foo" "bar" } } "localhost" <post-request> request>string
29     "7" "190" replace string>request post-data>> params>>
30 ] unit-test
31
32 { H{ { "name" "John Smith" } } } [
33     { { "name" "John Smith" } } "localhost" <post-request> request>string
34     string>request post-data>> params>>
35 ] unit-test
36
37 ! multipart/form-data
38 STRING: test-multipart/form-data
39 POST / HTTP/1.1
40 Accept: */*
41 Accept-Encoding: gzip, deflate
42 Connection: keep-alive
43 Content-Length: 151
44 Content-Type: multipart/form-data; boundary=768de80194d942619886d23f1337aa15
45 Host: localhost:8000
46 User-Agent: HTTPie/0.9.0-dev
47
48 --768de80194d942619886d23f1337aa15
49 Content-Disposition: form-data; name="text"; filename="upload.txt"
50
51 hello
52 --768de80194d942619886d23f1337aa15--
53
54 ;
55 {
56     "upload.txt"
57     H{
58         { "content-disposition"
59           "form-data; name=\"text\"; filename=\"upload.txt\"" }
60     }
61 } [
62     test-multipart/form-data normalize-nl string>request
63     post-data>> params>> "text" of [ filename>> ] [ headers>> ] bi
64 ] unit-test
65
66 ! Error handling
67 ! If the incoming request is not valid, read-request should throw an
68 ! appropriate error.
69 STRING: test-multipart/form-data-missing-boundary
70 POST / HTTP/1.1
71 Accept: */*
72 Accept-Encoding: gzip, deflate
73 Connection: keep-alive
74 Content-Length: 151
75 Content-Type: multipart/form-data; abcd
76 Host: localhost:8000
77 User-Agent: HTTPie/0.9.0-dev
78
79 --768de80194d942619886d23f1337aa15
80 Content-Disposition: form-data; name="text"; filename="upload.txt"
81
82 hello
83 --768de80194d942619886d23f1337aa15--
84
85 ;
86 [ test-multipart/form-data-missing-boundary string>request ]
87 [ no-boundary? ] must-fail-with
88
89 ! Relative urls are invalid.
90 [ "GET foo HTTP/1.1" string>request ] [ path>> "foo" = ] must-fail-with
91
92 ! Empty request lines
93 [ "" string>request ] [ parse-error>> parse-error? ] must-fail-with
94
95 ! Missing content-length is probably not ok. It's plausible
96 ! transfer-length could replace it, but we don't handle it atm anyway.
97 [
98     { { "foo" "bar" } } "localhost" <post-request> request>string
99     "content-length" "foo" replace string>request
100 ] [ content-length-missing? ] must-fail-with
101
102 ! Non-numeric content-length is ofc crap.
103 [
104     { { "foo" "bar" } } "localhost" <post-request> request>string
105     "7" "i am not a number!" replace string>request
106 ] [
107     [ invalid-content-length? ]
108     [ content-length>> "i am not a number!" = ] bi and
109 ] must-fail-with
110
111 ! Negative is it too.
112 [
113     { { "foo" "bar" } } "localhost" <post-request> request>string
114     "7" "-1234" replace string>request
115 ] [
116     [ invalid-content-length? ]
117     [ content-length>> -1234 = ] bi and
118 ] must-fail-with
119
120 ! And too big
121 [
122     { { "foo" "bar" } } "localhost" <post-request> request>string
123     "7" upload-limit get 1 + number>string replace string>request
124 ] [
125     [ invalid-content-length? ]
126     [ content-length>> upload-limit get 1 + = ] bi and
127 ] must-fail-with
128
129
130 ! RFC 2616: Section 4.1
131 ! In the interest of robustness, servers SHOULD ignore any empty
132 ! line(s) received where a Request-Line is expected. In other words, if
133 ! the server is reading the protocol stream at the beginning of a
134 ! message and receives a CRLF first, it should ignore the CRLF.
135 [
136     T{ request
137         { method "GET" }
138         { url URL" /" }
139         { version "1.0" }
140         { header H{ } }
141         { cookies V{ } }
142         { redirects 10 }
143     }
144 ] [
145     "\r\n\r\n\r\nGET / HTTP/1.0\r\n\r\n"
146     [ read-request ] with-string-reader
147 ] unit-test
148
149 ! RFC 2616: Section 19.3
150 ! The line terminator for message-header fields is the sequence CRLF.
151 ! However, we recommend that applications, when parsing such headers,
152 ! recognize a single LF as a line terminator and ignore the leading CR.
153 [ t ] [
154     {
155         "GET / HTTP/1.1"
156         "connection: close"
157         "host: 127.0.0.1:55532"
158         "user-agent: Factor http.client"
159     } [ "\n" join ] [ "\r\n" join ] bi
160     [ [ read-request ] with-string-reader ] same?
161 ] unit-test