pavone@157: { pavone@159: parseHex <- :text { pavone@159: } pavone@157: response <- :_headers _status _sock _data { pavone@157: _open? <- true pavone@157: _body <- "" pavone@157: _length <- int32: (_headers get: "Content-Length" withDefault: "-1") pavone@157: _chunked? <- (_headers get: "Transfer-Encoding" withDefault: "") = "chunked" pavone@157: _code <- int32: _status pavone@149: #{ pavone@157: headers <- { _headers } pavone@157: status <- { _status } pavone@157: statusCode <- { _code } pavone@157: body <- { pavone@157: if: _open? { pavone@157: if: _chunked? { pavone@159: chunkSize <- 0 pavone@159: while: { pavone@159: canReceive <- true pavone@159: while: { pavone@159: pos <- _data find: "\r\n" else: { -1 } pavone@159: if: pos >= 0 { pavone@159: chunkSize <- (_data from: 0 withLength: pos) parseHex32 pavone@159: _data <- _data from: pos + 2 pavone@159: false pavone@159: } else: { pavone@159: canReceive pavone@159: } pavone@159: } do: { pavone@159: r <- (_sock recv: 4096) pavone@159: if: (r length) > 0 { pavone@159: _data <- _data . r pavone@159: } else: { pavone@159: canReceive <- false pavone@159: } pavone@159: } pavone@159: chunkSize > 0 pavone@159: } do: { pavone@159: while: { (_data length) < chunkSize } do: { pavone@159: r <- _sock recv: 4096 pavone@159: if: (r length) > 0 { pavone@159: _data <- _data . r pavone@159: } else: { pavone@159: chunkSize <- _data length pavone@159: } pavone@159: } pavone@159: _body <- _body . (_data from: 0 withLength: chunkSize) pavone@159: } pavone@157: } else: { pavone@157: if: _length >= 0 { pavone@157: _body <- _data . (_sock recvAll: (_length - (_data byte_length))) pavone@157: } else: { pavone@157: chunk <- "" pavone@157: while: { pavone@157: chunk <- _sock recv: 4096 pavone@157: (chunk length) > 0 pavone@157: } do: { pavone@157: _data <- _data . chunk pavone@157: } pavone@157: _body <- _data pavone@157: } pavone@153: } pavone@157: _data <- "" pavone@157: close pavone@153: } pavone@157: _body pavone@157: } pavone@157: close <- { pavone@157: if: _open? { pavone@157: _sock close pavone@157: _open? <- false pavone@153: } pavone@149: } pavone@149: } pavone@149: } pavone@160: _handleResponse <- :sock { pavone@160: resp <- "" pavone@160: waiting <- true pavone@160: headerText <- "" pavone@160: rest <- "" pavone@160: status <- "" pavone@160: while: { waiting } do: { pavone@163: data <- sock recv: 4096 pavone@160: resp <- resp . data pavone@160: pos <- resp find: "\r\n\r\n" else: { -1 } pavone@160: if: pos >= 0 { pavone@160: waiting <- false pavone@160: statusEnd <- resp find: "\r\n" else: { 0 } pavone@160: statusStart <- (resp find: " " else: { 0 }) + 1 pavone@160: status <- resp from: statusStart withLength: (statusEnd - statusStart) pavone@160: headerText <- resp from: statusEnd + 2 withLength: pos - (statusEnd + 2) pavone@160: rest <- resp from: pos + 4 pavone@160: } pavone@160: } pavone@160: headers <- (headerText splitOn: "\r\n") fold: (dict linear) with: :acc curLine{ pavone@160: //TODO: support multiple headers with the same name pavone@160: part <- curLine partitionOn: ":" pavone@160: acc set: (trim: (part before)) (trim: (part after)) pavone@160: } pavone@160: pavone@160: response: headers status sock rest pavone@160: } pavone@157: #{ pavone@157: client:usingPort <- :address :port{ pavone@157: #{ pavone@157: get <- :path { pavone@157: sock <- socket connectTo: address onPort: port pavone@157: sock send: "GET " . path . " HTTP/1.1\r\nHost: " . address . "\r\n\r\n" pavone@160: _handleResponse: sock pavone@160: } pavone@160: post:toPath:withType <- :body :path :type { pavone@160: sock <- socket connectTo: address onPort: port pavone@160: 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: sock send: body pavone@160: _handleResponse: sock pavone@157: } pavone@157: } pavone@157: } pavone@157: pavone@157: client <- :address { pavone@157: client: address usingPort: 80 pavone@157: } pavone@149: } pavone@149: }