pavone@157
|
1 {
|
pavone@159
|
2 parseHex <- :text {
|
pavone@159
|
3 }
|
pavone@157
|
4 response <- :_headers _status _sock _data {
|
pavone@157
|
5 _open? <- true
|
pavone@157
|
6 _body <- ""
|
pavone@157
|
7 _length <- int32: (_headers get: "Content-Length" withDefault: "-1")
|
pavone@157
|
8 _chunked? <- (_headers get: "Transfer-Encoding" withDefault: "") = "chunked"
|
pavone@157
|
9 _code <- int32: _status
|
pavone@149
|
10 #{
|
pavone@157
|
11 headers <- { _headers }
|
pavone@157
|
12 status <- { _status }
|
pavone@157
|
13 statusCode <- { _code }
|
pavone@157
|
14 body <- {
|
pavone@157
|
15 if: _open? {
|
pavone@157
|
16 if: _chunked? {
|
pavone@159
|
17 chunkSize <- 0
|
pavone@159
|
18 while: {
|
pavone@159
|
19 canReceive <- true
|
pavone@159
|
20 while: {
|
pavone@159
|
21 pos <- _data find: "\r\n" else: { -1 }
|
pavone@159
|
22 if: pos >= 0 {
|
pavone@159
|
23 chunkSize <- (_data from: 0 withLength: pos) parseHex32
|
pavone@159
|
24 _data <- _data from: pos + 2
|
pavone@159
|
25 false
|
pavone@159
|
26 } else: {
|
pavone@159
|
27 canReceive
|
pavone@159
|
28 }
|
pavone@159
|
29 } do: {
|
pavone@159
|
30 r <- (_sock recv: 4096)
|
pavone@159
|
31 if: (r length) > 0 {
|
pavone@159
|
32 _data <- _data . r
|
pavone@159
|
33 } else: {
|
pavone@159
|
34 canReceive <- false
|
pavone@159
|
35 }
|
pavone@159
|
36 }
|
pavone@159
|
37 chunkSize > 0
|
pavone@159
|
38 } do: {
|
pavone@159
|
39 while: { (_data length) < chunkSize } do: {
|
pavone@159
|
40 r <- _sock recv: 4096
|
pavone@159
|
41 if: (r length) > 0 {
|
pavone@159
|
42 _data <- _data . r
|
pavone@159
|
43 } else: {
|
pavone@159
|
44 chunkSize <- _data length
|
pavone@159
|
45 }
|
pavone@159
|
46 }
|
pavone@159
|
47 _body <- _body . (_data from: 0 withLength: chunkSize)
|
pavone@159
|
48 }
|
pavone@157
|
49 } else: {
|
pavone@157
|
50 if: _length >= 0 {
|
pavone@157
|
51 _body <- _data . (_sock recvAll: (_length - (_data byte_length)))
|
pavone@157
|
52 } else: {
|
pavone@157
|
53 chunk <- ""
|
pavone@157
|
54 while: {
|
pavone@157
|
55 chunk <- _sock recv: 4096
|
pavone@157
|
56 (chunk length) > 0
|
pavone@157
|
57 } do: {
|
pavone@157
|
58 _data <- _data . chunk
|
pavone@157
|
59 }
|
pavone@157
|
60 _body <- _data
|
pavone@157
|
61 }
|
pavone@153
|
62 }
|
pavone@157
|
63 _data <- ""
|
pavone@157
|
64 close
|
pavone@153
|
65 }
|
pavone@157
|
66 _body
|
pavone@157
|
67 }
|
pavone@157
|
68 close <- {
|
pavone@157
|
69 if: _open? {
|
pavone@157
|
70 _sock close
|
pavone@157
|
71 _open? <- false
|
pavone@153
|
72 }
|
pavone@149
|
73 }
|
pavone@149
|
74 }
|
pavone@149
|
75 }
|
pavone@160
|
76 _handleResponse <- :sock {
|
pavone@160
|
77 resp <- ""
|
pavone@160
|
78 waiting <- true
|
pavone@160
|
79 headerText <- ""
|
pavone@160
|
80 rest <- ""
|
pavone@160
|
81 status <- ""
|
pavone@160
|
82 while: { waiting } do: {
|
pavone@163
|
83 data <- sock recv: 4096
|
pavone@160
|
84 resp <- resp . data
|
pavone@160
|
85 pos <- resp find: "\r\n\r\n" else: { -1 }
|
pavone@160
|
86 if: pos >= 0 {
|
pavone@160
|
87 waiting <- false
|
pavone@160
|
88 statusEnd <- resp find: "\r\n" else: { 0 }
|
pavone@160
|
89 statusStart <- (resp find: " " else: { 0 }) + 1
|
pavone@160
|
90 status <- resp from: statusStart withLength: (statusEnd - statusStart)
|
pavone@160
|
91 headerText <- resp from: statusEnd + 2 withLength: pos - (statusEnd + 2)
|
pavone@160
|
92 rest <- resp from: pos + 4
|
pavone@160
|
93 }
|
pavone@160
|
94 }
|
pavone@160
|
95 headers <- (headerText splitOn: "\r\n") fold: (dict linear) with: :acc curLine{
|
pavone@160
|
96 //TODO: support multiple headers with the same name
|
pavone@160
|
97 part <- curLine partitionOn: ":"
|
pavone@160
|
98 acc set: (trim: (part before)) (trim: (part after))
|
pavone@160
|
99 }
|
pavone@160
|
100
|
pavone@160
|
101 response: headers status sock rest
|
pavone@160
|
102 }
|
pavone@157
|
103 #{
|
pavone@157
|
104 client:usingPort <- :address :port{
|
pavone@157
|
105 #{
|
pavone@157
|
106 get <- :path {
|
pavone@157
|
107 sock <- socket connectTo: address onPort: port
|
pavone@157
|
108 sock send: "GET " . path . " HTTP/1.1\r\nHost: " . address . "\r\n\r\n"
|
pavone@160
|
109 _handleResponse: sock
|
pavone@160
|
110 }
|
pavone@160
|
111 post:toPath:withType <- :body :path :type {
|
pavone@160
|
112 sock <- socket connectTo: address onPort: port
|
pavone@160
|
113 sock send: "POST " . path . " HTTP/1.1\r\nHost: " . address . "\r\nContent-Type: " . type . "\r\nContent-Length: " . (string: (body byte_length)) . "\r\n\r\n"
|
pavone@160
|
114 sock send: body
|
pavone@160
|
115 _handleResponse: sock
|
pavone@157
|
116 }
|
pavone@157
|
117 }
|
pavone@157
|
118 }
|
pavone@157
|
119
|
pavone@157
|
120 client <- :address {
|
pavone@157
|
121 client: address usingPort: 80
|
pavone@157
|
122 }
|
pavone@149
|
123 }
|
pavone@149
|
124 }
|