changeset 157:55e0dca7d3d7

Partial implementation of HTTP get requests
author Mike Pavone <pavone@retrodev.com>
date Sat, 10 Aug 2013 15:06:56 -0700
parents d6e79885bd3b
children 38140b7dbe3d
files modules/http.tp modules/string.tp samples/http.tp
diffstat 3 files changed, 109 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/modules/http.tp	Sat Aug 10 14:50:38 2013 -0700
+++ b/modules/http.tp	Sat Aug 10 15:06:56 2013 -0700
@@ -1,41 +1,83 @@
-#{
-	client:usingPort <- :address :port{
+{
+	response <- :_headers _status _sock _data {
+		_open? <- true
+		_body <- ""
+		_length <- int32: (_headers get: "Content-Length" withDefault: "-1")
+		_chunked? <- (_headers get: "Transfer-Encoding" withDefault: "") = "chunked"
+		_code <- int32: _status
 		#{
-			get <- :path {
-				sock <- socket connectTo: address onPort: port
-				sock send: "GET " . path . " HTTP/1.1\r\nHost: " . address . "\r\n\r\n"
-				resp <- ""
-				waiting <- true
-				headerText <- ""
-				rest <- ""
-				while: { waiting } do: {
-					data <- sock recv 4096
-					resp <- resp . data
-					pos <- resp find: "\r\n\r\n" else: { -1 }
-					if: pos >= 0 {
-						waiting <- false
-						headerText <- resp from: 0 withLength: pos
-						rest <- resp from: pos + 4
+			headers <- { _headers }
+			status <- { _status }
+			statusCode <- { _code }
+			body <- {
+				if: _open? {
+					if: _chunked? {
+
+					} else: {
+						if: _length >= 0 {
+							_body <- _data . (_sock recvAll: (_length - (_data byte_length)))
+						} else: {
+							chunk <- ""
+							while: {
+								chunk <- _sock recv: 4096
+								(chunk length) > 0
+							} do: {
+								_data <- _data . chunk
+							}
+							_body <- _data
+						}
 					}
+					_data <- ""
+					close
 				}
-				print: "Headers:\n" . headerText . "\n"
-				print: "Rest:\n" . rest . "\n"
-				_headers <- (headerText split: "\r\n") fold: (dict linear) with: :acc curLine{
-					//TODO: support multiple headers with the same name
-					part <- curLine partitionOn: ":"
-					acc set: (part before) (trim: (part after))
+				_body
+			}
+			close <- {
+				if: _open? {
+					_sock close
+					_open? <- false
 				}
-				_closed <- false
-				#{
-
-				}
-				sock close
-				rest
 			}
 		}
 	}
+	#{
+		client:usingPort <- :address :port{
+			#{
+				get <- :path {
+					sock <- socket connectTo: address onPort: port
+					sock send: "GET " . path . " HTTP/1.1\r\nHost: " . address . "\r\n\r\n"
+					resp <- ""
+					waiting <- true
+					headerText <- ""
+					rest <- ""
+					status <- ""
+					while: { waiting } do: {
+						data <- sock recv 4096
+						resp <- resp . data
+						pos <- resp find: "\r\n\r\n" else: { -1 }
+						if: pos >= 0 {
+							waiting <- false
+							statusEnd <- resp find: "\r\n" else: { 0 }
+							statusStart <- (resp find: " " else: { 0 }) + 1
+							status <- resp from: statusStart withLength: (statusEnd - statusStart)
+							headerText <- resp from: statusEnd + 2 withLength: pos - (statusEnd + 2)
+							rest <- resp from: pos + 4
+						}
+					}
+					headers <- (headerText splitOn: "\r\n") fold: (dict linear) with: :acc curLine{
+						//TODO: support multiple headers with the same name
+						part <- curLine partitionOn: ":"
+						acc set: (trim: (part before)) (trim: (part after))
+					}
 
-	client <- :address {
-		client: address usingPort: 80
+
+					response: headers status sock rest
+				}
+			}
+		}
+
+		client <- :address {
+			client: address usingPort: 80
+		}
 	}
 }
--- a/modules/string.tp	Sat Aug 10 14:50:38 2013 -0700
+++ b/modules/string.tp	Sat Aug 10 15:06:56 2013 -0700
@@ -187,6 +187,34 @@
 		pieces append: self
 	}
 
+	trim <- {
+		l <- length
+		start <- 0
+		space <- " " byte: 0
+		tab <- "\t" byte: 0
+		nl <- "\n" byte: 0
+		cr <- "\r" byte: 0
+
+		while: {
+			if: start < l {
+				b <- byte: start
+				b = space || b = tab || b = nl || b = cr
+			}
+		} do: {
+			start <- start + 1
+		}
+		end <- l
+		while: {
+			if: end > 0 {
+				b <- byte: end
+				b = space || b = tab || b = nl || b = cr
+			}
+		} do: {
+			end <- end + 1
+		}
+		from: start withLength: (end - start)
+	}
+
 	isInteger? <- { false }
 	isString? <- { true }
 }
--- a/samples/http.tp	Sat Aug 10 14:50:38 2013 -0700
+++ b/samples/http.tp	Sat Aug 10 15:06:56 2013 -0700
@@ -5,6 +5,13 @@
 			server <- args get: 1
 		}
 		cli <- http client: server
-		print: (string: (cli get: "/"))
+		resp <- (cli get: "/")
+		print: "Status: " . (resp status) . "\n"
+		print: "Code: " . (resp statusCode) . "\n"
+		print: "Headers:\n"
+		foreach: (resp headers) :key val {
+			print: key . " -> " . val . "\n"
+		}
+		print: "Body:\n" . (resp body) . "\n"
 	}
 }