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