HttpContext: Lightweight HTTP protocol support.

This commit is contained in:
Jonathan Bernard 2013-03-14 04:50:43 -05:00
parent c887a49f8c
commit db15eb8f88

View File

@ -0,0 +1,134 @@
/** @author Jonathan Bernard (jdbernard@gmail.com)
* @copyright 2013 Jonathan Bernard. */
package com.jdbernard.net
import java.net.Socket
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
/** Helper class to perform basic HTTP communication. */
public class HttpContext {
/** The host to which this object will connect. This also affects the
* `Host` header in requests. */
public String host = 'vbs-test'
/** The port number.*/
public int port = 8000
/** A cookie value to send in the request. This value will be automatically
* set from any `Set-Cookie` header in the request response. */
public String cookie
/** #### makeMessage
* Make and return an HTTP request for the given HTTP method and URL. If
* `request` is not null, it is expected to be an object which will be
* converted to JSON and included as the request body. The `Host`,
* `Cookie`, and `Content-Length` headers will be added based on the
* `host` and `cookie` fields and the `request` object. */
public String makeMessage(String method, String url, def request) {
StringBuilder message = new StringBuilder()
message.append(method)
message.append(" ")
message.append(url)
message.append(" HTTP/1.1\r\n")
if (host && port) {
message.append("Host: ")
message.append(host)
message.append(":")
message.append(port)
message.append("\r\n") }
if (cookie) {
message.append("Cookie: ")
message.append(cookie)
message.append("\r\n") }
if (request) {
def jsonRequestBuilder = new JsonBuilder(request)
String requestBody = jsonRequestBuilder.toString()
message.append("Content-Length: ")
message.append(requestBody.length())
message.append("\r\n\r\n")
message.append(requestBody) }
message.append("\r\n")
return message.toString()
}
/** #### send
* A wrapper around `makeMessage` and `send(String message)` to create a
* request, send it, and return the response. */
public def send(String method, String url, def request) {
return send(makeMessage(method, url, request)) }
/** #### send
* Send a message to the host specified by the object's `host` and `port`
* fields and parses the response. Returns an object with the following
* properties:
*
* - `status`: the HTTP response status (200, 404, etc.).
* - `headers`: A list of header lines (one line per list entry).
* - `content`: the response body (expected as JSON from the server) parsed
* into a Groovy object.
* - `responseTime`: the time measured immediately after the client flushes
* its output buffer to the time it completely reads the server response.
*/
public def send(String message) {
Map result = [headers:[], content: null]
Socket sock = new Socket(host, port)
def startTime
sock.withStreams { strin, out ->
def writer = new BufferedWriter(new OutputStreamWriter(out))
def reader = new BufferedReader(new InputStreamReader(strin))
int bytesExpected
writer.write(message)
startTime = System.currentTimeMillis()
writer.flush()
def line = reader.readLine().trim()
result.status = line.split(/\s/)[1]
line = reader.readLine().trim()
while(line) {
def m = (line =~ /Content-Length: (\d+)/)
if (m) bytesExpected = m[0][1] as int
m = (line =~ /Set-Cookie: ([^=]+=[^;]+);.+/)
if (m) this.cookie = m[0][1]
result.headers << line
line = reader.readLine() }
if (bytesExpected) {
StringBuilder sb = new StringBuilder()
for (int i = 0; i < bytesExpected; i++) {
sb.append(reader.read() as char) }
result.responseTime = System.currentTimeMillis() - startTime
try { result.content = new JsonSlurper().parseText(sb.toString()) }
catch (Exception e) { result.content = sb.toString() } }
else
result.responseTime = System.currentTimeMillis() - startTime
}
sock.close()
return result
}
/** #### get
* A wrapper to perform a simple `GET` request. This calls
* `send(String method, String url, def request)` with `method = "GET"`,
* and `request = null`. */
public def get(String url) { return send('GET', url, null) }
/** #### post
* A wrapper to perform a `POST` request. This calls
* `send(String method, String url, def request)` with `method =
* "POST"`. */
public def post(String url, def body) { return send('POST', url, body) }
}