annotate modules/http.tp @ 253:697c2c562af2

Fix infinite loop in hash dict
author Michael Pavone <pavone@retrodev.com>
date Sat, 31 May 2014 21:27:03 -0700
parents f594e6836c44
children
rev   line source
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 }