HTTPReq{{ /** Create an HTTP Request with a given Header, MessageHeaders, and Body */ public static HTTPReq create(HTTPHead req, List hds, String body){ return new HTTPReq(req, hds.append(new MsgHead("Content-Length",""+body.length())), new ident(body)); } /** Create an HTTP Get Request for the given (relative) URL. Then use * {@link HTTPReq.send 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 HTTPReq.send 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 HTTPReq.send 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 HTTPReq.send 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 HTTPReq.send 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 HTTPReq.send 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 */ HTTPReq addHeaders(List hs){ return create(head,hs.append(keys),""+body); } /** Request Types */ public static enum ReqType{ GET, POST, HEAD, 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(); } /** Handle this Request with the given Handler */ public HTTPResp handle(ReqHandler h){ return head.handle(this,h); } /** Send this Request to the given Server/Port, and return its Response */ public HTTPResp send(String server, int port) throws IOException { Socket sock = new Socket(server, port); addHeaders(hostHeader(server+":"+port)).toSocket(sock); HTTPResp res = HTTPResp.fromSocket(sock); sock.close(); return res; } /** Write this Request to the given Socket */ public void toSocket(Socket s){ try{ PrintWriter out = new PrintWriter(s.getOutputStream()); out.print(this.toString()); out.flush(); s.shutdownOutput(); }catch(Exception e){ throw new RuntimeException(e); } } /** Read a request from a Socket */ public static HTTPReq fromSocket(Socket s){ try{ HTTPReq req = fromInputStream(s.getInputStream()); s.shutdownInput(); return req; }catch(Exception e){ throw new RuntimeException(e); } } /** Read a Request from an InputStream */ public static HTTPReq fromInputStream(InputStream inpt){ try{ BufferedReader in = new BufferedReader(new InputStreamReader(inpt)); HTTPHead h = HTTPHead.parse(in.readLine()); return new HTTPReq(h, parseMsgHeads(in), parseBody(in)); }catch(Exception e){ throw new RuntimeException(e); } } /** Parse a List of Message Headers */ static List parseMsgHeads(BufferedReader in) throws Exception{ String line; if(!in.ready() || (line = in.readLine()).length()==0) return List.create(); int colon = line.indexOf(":"); return parseMsgHeads(in).push(new MsgHead(new ident(line.substring(0,colon)), new ident(line.substring(colon+2)))); } /** Parse the Body of a Request */ static ident parseBody(BufferedReader in) throws Exception{ StringBuffer sb = new StringBuffer(); char[] buff = new char[1024]; int many = 0; if(in.ready()) do{ many = in.read(buff); sb.append(buff,0,many); }while(in.ready() && many == 1024); return new ident(sb.toString()); } /** Return the Body of this Request */ public String getBody(){ return ""+body; } /** 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(kv[0],kv[1]); } }, Map.create()); } }} HTTPResp{{ /** Basic Response Numbers */ public static final int OK = 200, ERROR = 404; /** Typical HTTP Version */ public static final HTTPVer VER = new HTTPVer(1.0); /** Create a response with the given number, description, headers, and body */ public static HTTPResp create(int resp, String desc, List hds, String body){ return new HTTPResp(VER, resp, new ident(desc), hds.append(new MsgHead("Content-Length",""+body.length())), new ident(body)); } /** Create an OK Response with the given Content-Type/Body */ public static HTTPResp ok(String type, String body){ return create(OK, "OK", commonHeaders(type), body); } /** Common Headers: Date, Content-Type */ private static List commonHeaders(String type){ return List.create( new MsgHead("Date",""+new java.util.Date()), new MsgHead("Content-Type",type)); } /** Create an (empty) Error Response */ public static HTTPResp error(){ return error(""); } /** Create an Error Response with a Body */ public static HTTPResp error(String body){ return create(ERROR, "Not Found", commonHeaders("text/plain"), body); } /** Create a Plain Text Response */ public static HTTPResp textResponse(String text){ return ok("text/plain", text); } /** Create an HTML Response */ public static HTTPResp htmlResponse(String text){ return ok("text/html", text); } /** Is this Response OK? */ public boolean isOK(){ return resp == OK; } /** Is this Response an Error? */ public boolean isError(){ return resp == ERROR; } /** Write a Response to a Socket */ public void toSocket(Socket s){ try{ PrintWriter out = new PrintWriter(s.getOutputStream()); out.print(this.toString()); out.flush(); s.shutdownOutput(); }catch(Exception e){ throw new RuntimeException(e); } } /** Read a Response from a Socket */ public static HTTPResp fromSocket(Socket s){ try{ HTTPResp resp = fromInputStream(s.getInputStream()); s.shutdownInput(); return resp; }catch(Exception e){ throw new RuntimeException(e); } } /** Read a Response from an Input Stream */ public static HTTPResp fromInputStream(InputStream inpt){ try{ BufferedReader in = new BufferedReader(new InputStreamReader(inpt)); String first = in.readLine(); HTTPVer v = HTTPVer.parse(first); first = first.substring(first.indexOf(' ')+1); int b = first.indexOf(' '), rnum = Integer.parseInt(first.substring(0,b)); return new HTTPResp(v, rnum, new ident(first.substring(b+1)), HTTPReq.parseMsgHeads(in), HTTPReq.parseBody(in)); }catch(Exception e){ throw new RuntimeException(e); } } /** Get the body of this Response */ public String getBody(){ return ""+body; } /** Return the headers (key/value Map) of this Response */ public Map getHeaders(){ return HTTPReq.getHeaders(keys); } }} HTTPHead{{ /** Get the ReqType of this Request */ public HTTPReq.ReqType getType(){ return HTTPReq.ReqType.OTHER; } /** Handle a Request using a ReHandler */ public HTTPResp handle(HTTPReq r, ReqHandler h){ return h.other(r); } /** Return a Get Request for the given URL */ public static HTTPHead Get(URL url) { return new GetReq(url, HTTPResp.VER); } /** Return a Head Request for the given URL */ public static HTTPHead Head(URL url) { return new HeadReq(url, HTTPResp.VER); } /** Return a Post Request for the given URL */ public static HTTPHead Post(URL url) { return new PostReq(url, HTTPResp.VER); } }} GetReq{{ /** Get the ReqType of this Request */ public HTTPReq.ReqType getType(){ return HTTPReq.ReqType.GET; } /** Handle a Request using a ReHandler */ public HTTPResp handle(HTTPReq r, ReqHandler h){ return h.get(r); } }} PostReq{{ /** Get the ReqType of this Request */ public HTTPReq.ReqType getType(){ return HTTPReq.ReqType.POST; } /** Handle a Request using a ReHandler */ public HTTPResp handle(HTTPReq r, ReqHandler h){ return h.post(r); } }} HeadReq{{ /** Get the ReqType of this Request */ public HTTPReq.ReqType getType(){ return HTTPReq.ReqType.HEAD; } /** Handle a Request using a ReHandler */ public HTTPResp handle(HTTPReq r, ReqHandler h){ return h.head(r); } }} MsgHead{{ /** Create a MsgHeader from key/value Strings */ public MsgHead(String k, String v){ this(new ident(k), new ident(v)); } }} URL{{ /** Is this URL Empty? */ public boolean isEmpty(){ return false; } /** Return the URLs Arguments */ public abstract Map urlArgs(); /** Remove the URLs Arguments */ public abstract String trimArgs(); }} NoURL{{ /** Is this URL Empty? */ public boolean isEmpty(){ return true; } /** Return the URLs Arguments */ public Map urlArgs(){ return Map.create(); } /** Remove the URLs Arguments */ public String trimArgs(){ return ""; } }} BaseURL{{ /** Return the URLs Arguments */ public Map urlArgs(){ return rest.urlArgs(); } /** Remove the URL Arguments */ public String trimArgs(){ return "/"+rest.trimArgs(); } }} MidURL{{ /** Return the URLs Arguments */ public Map urlArgs(){ Map r = rest.urlArgs(); if(!rest.isEmpty())return r; String idS = id.toString(); int amp = idS.indexOf('?'); if(amp<0)return r; idS = idS.substring(idS.indexOf('?')+1).trim(); return HTTPReq.splitArgs(idS); } /** Remove the URLs Arguments */ public String trimArgs(){ if(!rest.isEmpty())return id+rest.trimArgs(); String idS = id.toString(); int amp = idS.indexOf('?'); return amp<0 ? idS: idS.substring(0,amp); } }} ReqHandler{{ /** Respond to a possible ServerSocket Connection */ public void respond(ServerSocket s){ try{ respond(s.accept()); }catch(IOException io){ throw new RuntimeException(io); } } /** Respond to a Socket Connection */ public void respond(Socket in){ try{ HTTPReq req = HTTPReq.fromSocket(in); HTTPResp resp = req.handle(this); resp.toSocket(in); in.close(); }catch(IOException io){ throw new RuntimeException(io); } } /** Handle a GET request */ public HTTPResp get(HTTPReq r){ return other(r); } /** Handle a POST request */ public HTTPResp post(HTTPReq r){ return other(r); } /** Handle a HEAD request */ public HTTPResp head(HTTPReq r){ return other(r); } /** Handle any Other/unknown request */ public HTTPResp other(HTTPReq r){ return HTTPResp.ok("text/plain",""); } }}