// ** This class was generated with DemFGen (vers:11/09/2009) package edu.neu.ccs.demeterf.http.classes; import edu.neu.ccs.demeterf.lib.*; import java.net.Socket; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.io.IOException; import java.io.BufferedReader; import java.io.PrintWriter; import java.io.InputStreamReader; import java.io.InputStream; /** Representation of HTTPReq */ public class HTTPReq{ protected final HTTPHead head; protected final List keys; protected final ident body; /** Construct a(n) HTTPReq Instance */ public HTTPReq(HTTPHead head, List keys, ident body){ this.head = head; this.keys = keys; this.body = body; } /** Is the given object Equal to this HTTPReq? */ public boolean equals(Object o){ if(!(o instanceof HTTPReq))return false; if(o == this)return true; HTTPReq oo = (HTTPReq)o; return (((Object)head).equals(oo.head))&&(((Object)keys).equals(oo.keys))&&(((Object)body).equals(oo.body)); } /** Field Class for HTTPReq.head */ public static class head extends edu.neu.ccs.demeterf.Fields.any{} /** Field Class for HTTPReq.keys */ public static class keys extends edu.neu.ccs.demeterf.Fields.any{} /** Field Class for HTTPReq.body */ public static class body extends edu.neu.ccs.demeterf.Fields.any{} /** Default Socket connection timeout (20 seconds) */ public static final int DEFAULT_CONN_TIMEOUT = 20*1000; /** Default Socket Response timeout (1 second) */ public static final int DEFAULT_RESP_TIMEOUT = 500; /** Create an HTTP Request with a given Header, MessageHeaders, and Body */ public static HTTPReq create(HTTPHead req, List hds, String body){ return createNoLen(req, hds.append(new MsgHead("Content-Length",""+body.length())), body); } /** Create an HTTP Request with a given Header, MessageHeaders, and Body */ private static HTTPReq createNoLen(HTTPHead req, List hds, String body){ return new HTTPReq(req, hds, new ident(body)); } /** Create an HTTP Get Request for the given (relative) URL. Then use * {@link #send(String,int) Send} for a Request/Response pair. */ public static HTTPReq Get(String url) throws ParseException { return create(HTTPHead.Get(URL.parse(url)), List.create(), ""); } /** Create an HTTP Get Request for the given relative URL, to be sent to the * given Host. Use this method for raw Socket/Connection sends, but use * {@link #send(String,int) Send} for a Request/Response pair. */ public static HTTPReq Get(String url, String host) throws ParseException { return create(HTTPHead.Get(URL.parse(url)), hostHeader(host), ""); } /** Create an HTTP Head Request for the given (relative) URL. Then use * {@link #send(String,int) Send} for a Request/Response pair. */ public static HTTPReq Head(String url) throws ParseException { return create(HTTPHead.Get(URL.parse(url)), List.create(), ""); } /** Create an HTTP Head Request for the given relative URL, to be sent to the * given Host. Use this method for raw Socket/Connection sends, but use * {@link #send(String,int) Send} for a Request/Response pair. */ public static HTTPReq Head(String url, String host) throws ParseException { return create(HTTPHead.Head(URL.parse(url)), hostHeader(host), ""); } /** Create an HTTP Post Request to the given (relative) URL. Then use * {@link #send(String,int) Send} for a Request/Response pair. */ public static HTTPReq Post(String url, String body) throws ParseException { return create(HTTPHead.Post(URL.parse(url)), List.create(), body); } /** Create an HTTP Post Request to the given relative URL, to be sent to the * given Host. Use this method for raw Socket/Connection sends, but use * {@link #send(String,int) Send} for a Request Response Pair. */ public static HTTPReq Post(String url, String host, String body) throws ParseException { return create(HTTPHead.Post(URL.parse(url)), hostHeader(host), body); } private static List hostHeader(String h) { return List.create(new MsgHead(new ident("Host"), new ident(h))); } /** Add the given Message Headers to this Request */ private HTTPReq addHeaders(List hs){ return createNoLen(head,hs.append(keys),""+body); } /** Add a given Message Headers to this Request */ public HTTPReq addHeader(String key, String val){ return createNoLen(head,keys.append(new MsgHead(key,val)),""+body); } /** Request Types */ public static enum ReqType{ GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, OPTIONS, OTHER }; /** Return this Request's type */ public ReqType getType(){ return head.getType(); } /** Return the URL arguments (key/value) for this request. The URL arguments * follow the base URL after a '?'. * E.g.: /foo/bar?bazzle=13&wizwoz='hello' */ public Map urlArgs(){ return head.url.urlArgs(); } /** Return the Body arguments (key/value) from this request. The Body arguments * are on a single line of the body, like URLArgs, but without the '?' */ public Map bodyArgs(){ return splitArgs(""+body); } /** Return the relative URL, without any URL arguments */ public String trimmedUrl(){ return head.url.trimArgs(); } /** Send this Request to the given Server/Port, and return its Response */ public HTTPResp send(String server, int port) throws IOException { return send(server,port,0); } /** Send this Request to the given Server/Port, and return its Response with * the given response timeout. If the server does not respond in the given * time a Socket exception will eb thrown */ public HTTPResp send(String server, int port, int respTimeout) throws IOException { return send(server,port,HTTPReq.DEFAULT_CONN_TIMEOUT, respTimeout, 0); } /** Send this Request to the given Server/Port, and return its Response with * the given response timeout, and limit the max response size to maxResp */ public HTTPResp send(String server, int port, int respTimeout, long maxResp) throws IOException { return send(server,port,HTTPReq.DEFAULT_CONN_TIMEOUT, respTimeout, maxResp); } /** Send this Request to the given Server/Port, and return its * Response, wait for the specified timout (in Milliseconds), and only * accept up to "maxResp" bytes */ public HTTPResp send(String server, int port, int connTimeout, int respTimeout, long maxResp) throws IOException { Socket sock = new Socket(); // Connect to the Server... timeout if not available sock.connect(new InetSocketAddress(server, port), connTimeout); // Add the Host header and send it to a socket addHeaders(hostHeader(server+":"+port)).toSocket(sock); // Read the response from the Socket, but timeout if needed HTTPResp res = HTTPResp.fromSocket(sock, respTimeout, maxResp); sock.close(); return res; } /** Write this Request to the given Socket */ public void toSocket(Socket s){ try{ PrintWriter outt = new PrintWriter(s.getOutputStream()); outt.print(this.toString()); outt.flush(); s.shutdownOutput(); }catch(IOException e){ throw new RuntimeException(e); } } /** Read a request from a Socket, without a timeout (wait forever) */ public static HTTPReq fromSocket(Socket s){ return fromSocket(s,0,0); } /** Read a request from a Socket, wait forever, but limit the transmission */ public static HTTPReq fromSocket(Socket s, long maxBytes){ return fromSocket(s,0,maxBytes); } /** Read a request from a Socket, timeout if needed */ public static HTTPReq fromSocket(Socket s, int respTimeout, long maxBytes){ try{ // Set a timeout on the response s.setSoTimeout(DEFAULT_RESP_TIMEOUT); HTTPReq req = fromInputStream(s.getInputStream(),respTimeout,maxBytes); s.shutdownInput(); return req; }catch(IOException e){ throw new RuntimeException(e); } } /** Read a Request from an InputStream with the given Timeout */ private static HTTPReq fromInputStream(InputStream inpt, long timeout, long maxBytes){ try{ BufferedReader inn = new BufferedReader(new InputStreamReader(inpt)); String first = readLine(inn,timeout); if(first == null)throw new RuntimeException("Empty HTTP Header"); HTTPHead h = HTTPHead.parse(first); HTTPReq.CountHds headers = HTTPReq.parseMsgHeads(inn,timeout,maxBytes,maxBytes-(first.length()+1)); return new HTTPReq(h, headers.heads, HTTPReq.parseBody(inn,timeout,maxBytes, maxBytes-(first.length()+1+headers.size))); }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new RuntimeException(e); } } /** Keep track of the bytes read for the headers */ static class CountHds{ public long size; public List heads; public CountHds(long s, List hds){ size = s; heads = hds; } public CountHds add(long s, MsgHead hd){ return new CountHds(s+size, heads.push(hd)); } } /** Parse a List of Message Headers */ static CountHds parseMsgHeads(BufferedReader in, long timeout, long maxBytes, long bytesLeft) throws Exception{ checkMaxBytes(maxBytes, bytesLeft); String line; if((line = readLine(in,timeout)) == null || line.length() == 0) return new CountHds(0, List.create()); int colon = line.indexOf(":"); return parseMsgHeads(in,timeout,maxBytes,bytesLeft-(line.length()+1)) .add(line.length()+1, new MsgHead(new ident(line.substring(0,colon)), new ident(line.substring(colon+2)))); } /** Read a single Line */ static String readLine(BufferedReader inn, long timeout) throws IOException{ long start = System.currentTimeMillis(); String line = ""; while(true){ line = null; try{ line = inn.readLine(); return line; }catch(java.net.SocketTimeoutException e){ if(timeout > 0 && (System.currentTimeMillis()-start) > timeout) throw e; } } } static void checkMaxBytes(long maxBytes, long bytesLeft){ if(maxBytes > 0 && bytesLeft < 0) throw new RuntimeException("HTTP Max Size Reached"); } /** Parse the Body of a Request */ static ident parseBody(BufferedReader inn, long timeout, long maxBytes, long bytesLeft) throws Exception{ checkMaxBytes(maxBytes, bytesLeft); long start = System.currentTimeMillis(); StringBuffer sb = new StringBuffer(); char[] buff = new char[1024]; int many; do{ many = 0; try{ many = inn.read(buff); if(many>0){ sb.append(buff,0,many); bytesLeft -= many; checkMaxBytes(maxBytes, bytesLeft); } }catch(java.net.SocketTimeoutException e){ if(timeout > 0 && (System.currentTimeMillis()-start) > timeout){ System.err.println("TIMEOUT: "+timeout+" TIME: "+(System.currentTimeMillis()-start)); throw new RuntimeException(e); } } }while(inn.ready() || many > 0); return new ident(sb.toString()); } /** Return the Body of this Request */ public String getBodyString(){ return body.toString(); } /** Return the Headers of this Request as a Map */ public Map getHeaders(){ return getHeaders(keys); } /** Return the Headers of this Request as a Map */ static Map getHeaders(List hds){ return hds.fold(new List.Fold>(){ public Map fold(MsgHead h, Map m){ return m.put(""+h.key,""+h.value); } }, Map.create()); } /** Split an argument String into key/value Map */ static Map splitArgs(String s){ return List.create(s.split("&")).fold(new List.Fold>(){ public Map fold(String p, Map m){ String[] kv = p.split("="); if(kv.length < 2)return m; return m.put(decodeURL(kv[0]),decodeURL(kv[1])); } }, Map.create()); } /** Decode an encoded URL */ public static String decodeURL(String url){ try{ return java.net.URLDecoder.decode(url, "UTF-8"); }catch(Exception e){ throw new RuntimeException(e); } } /** Encode a (possibly special) URL */ public static String encodeURL(String url){ try{ return java.net.URLEncoder.encode(url, "UTF-8"); }catch(Exception e){ throw new RuntimeException(e); } } /** DGP method from Class PrintHeapToString */ public String toString(){ return edu.neu.ccs.demeterf.http.classes.PrintHeapToString.PrintHeapToStringM(this); } /** Getter for field HTTPReq.body */ public ident getBody(){ return body; } /** Getter for field HTTPReq.keys */ public List getKeys(){ return keys; } /** Getter for field HTTPReq.head */ public HTTPHead getHead(){ return head; } }