package http_parser.lolevel;
import java.nio.*; import java.io.*; import java.util.*;
import http_parser.HTTPMethod; import http_parser.HTTPParserUrl; import http_parser.ParserType; import http_parser.lolevel.TestLoaderNG.Header; import http_parser.lolevel.TestLoaderNG.LastHeader;
import primitive.collection.ByteList;
import static http_parser.lolevel.Util.str;
public class Message {
String name; byte [] raw; ParserType type; HTTPMethod method; int status_code; String request_path; // byte [] ? String request_url; String fragment ; String query_string; byte [] body; int body_size; int num_headers; LastHeader last_header_element; Map<String,String> header; List<Header> headers; boolean should_keep_alive; byte[] upgrade; boolean upgrade() { return null != upgrade; } int http_major; int http_minor; boolean message_begin_called; boolean headers_complete_called; boolean message_complete_called; boolean message_complete_on_eof; Map<String,String> parsed_header; String currHField; String currHValue; byte [] pbody; int num_called; public String toString() { StringBuilder b = new StringBuilder(); b.append("NAME: "); b.append(name);b.append("\n"); b.append("type: "); b.append(type);b.append("\n"); b.append("method: "); b.append(method);b.append("\n"); b.append("status_code: "); b.append(status_code);b.append("\n"); b.append("request_path: "); b.append(request_path);b.append("\n"); b.append("request_url: "); b.append(request_url);b.append("\n"); b.append("fragment: "); b.append(fragment);b.append("\n"); b.append("query_string: "); b.append(query_string);b.append("\n"); b.append("body:\n"); b.append(new String(body));b.append("\n"); b.append("should_keep_alive: "); b.append(should_keep_alive);b.append("\n"); b.append("upgrade: "); b.append(upgrade);b.append("\n"); b.append("http_major: "); b.append(http_major);b.append("\n"); b.append("http_minor: "); b.append(http_minor);b.append("\n"); b.append("message_complete_called: "); b.append(message_complete_called);b.append("\n"); return b.toString(); } Message () { this.header = new HashMap<String, String>(); this.headers = new LinkedList<Header>(); reset(); } /* *prepare this Test Instance for reuse. * */ void reset () { this.parsed_header = new HashMap<String, String>(); this.pbody = null; this.num_called = 0; } void check (boolean val, String mes) { if (!val) { //p(name+" : "+mes); throw new RuntimeException(name+" : "+mes); } } HTTPDataCallback getCB (final String value, final String mes, final TestSettings settings) { return new HTTPDataCallback() { public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ // if ("url".equals(mes)){ // p("pos"+pos); // p("len"+len); // if (8==pos && 5 == len && "connect request".equals(name)) { // //throw new RuntimeException(name); // } // } //String str = str(b, pos, len); ByteList list = settings.map.get(mes); for (int i=0; i!=len; ++i) { list.add(b.get(pos+i)); } //settings.map.put(mes, prev_val + str); //check(value.equals(str), "incorrect "+mes+": "+str); if (-1 == pos) { throw new RuntimeException("he?"); } return 0; } }; } void execute () { p(name); ByteBuffer buf = ByteBuffer.wrap(raw); HTTPParser p = new HTTPParser(); TestSettings s = settings(); p.execute(s, buf); if (!p.upgrade) { // call execute again, else parser can't know message is done // if no content length is set. p.execute(s, buf); } if (!s.success) { throw new RuntimeException("Test: "+name+" failed"); } } // execute void execute_permutations() { /* |-|---------------| |--|--------------| |---|-------------| (...) |---------------|-| |-----------------| */ p(name); for (int i = 2; i != raw.length; ++i) { // p(i); HTTPParser p = new HTTPParser(); TestSettings s = settings(); ByteBuffer buf = ByteBuffer.wrap(raw); int olimit = buf.limit(); buf.limit(i); parse(p,s,buf); if (!p.upgrade) { buf.position(i); buf.limit(olimit); parse(p,s,buf); if (!p.upgrade) { parse(p,s,buf); } else { if (!upgrade()) { throw new RuntimeException("Test:"+name+"parsed as upgrade, is not"); } } } else { if (!upgrade()) { throw new RuntimeException("Test:"+name+"parsed as upgrade, is not"); } } if (!s.success) { p(this); throw new RuntimeException("Test: "+name+" failed"); } reset(); } //System.exit(0); } // execute_permutations void parse(HTTPParser p, ParserSettings s, ByteBuffer b) { //p("About to parse: "+b.position() + "->" + b.limit()); p.execute(s, b); } TestSettings settings() { final TestSettings s = new TestSettings(); s.on_url = getCB(request_url, "url", s); s.on_message_begin = new HTTPCallback() { public int cb (HTTPParser p) { message_begin_called = true; return -1; } }; s.on_header_field = new HTTPDataCallback() { public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ if (null != currHValue && null == currHField) { throw new RuntimeException(name+": shouldn't happen"); } if (null != currHField) { if (null == currHValue) { currHField += str(b,pos,len); return 0; } else { parsed_header.put(currHField, currHValue); currHField = null; currHValue = null; } } currHField = str(b,pos,len); return 0; } }; s.on_header_value = new HTTPDataCallback() { public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ if (null == currHField) { throw new RuntimeException(name+" :shouldn't happen field"); } if (null == currHValue) { currHValue = str(b,pos,len); } else { currHValue += str(b, pos, len); } return 0; } }; s.on_headers_complete = new HTTPCallback() { public int cb (HTTPParser p) { headers_complete_called = true; String parsed_path = null; String parsed_query = null; String parsed_url = null; String parsed_frag = null; try { parsed_url = new String(s.map.get("url").toArray(), "UTF8"); HTTPParserUrl u = new HTTPParserUrl(); HTTPParser pp = new HTTPParser(); ByteBuffer data = Util.buffer(parsed_url); pp.parse_url(data,false, u); parsed_path = u.getFieldValue(HTTPParser.UrlFields.UF_PATH, data); parsed_query = u.getFieldValue(HTTPParser.UrlFields.UF_QUERY, data); parsed_frag = u.getFieldValue(HTTPParser.UrlFields.UF_FRAGMENT, data); } catch (java.io.UnsupportedEncodingException uee) { throw new RuntimeException(uee); } if (!request_path.equals(parsed_path)) { throw new RuntimeException(name+": invalid path: "+parsed_path+" should be: "+request_path); } if (!query_string.equals(parsed_query)) { throw new RuntimeException(name+": invalid query: "+parsed_query+" should be: "+query_string); } if (!request_url.equals(parsed_url)) { throw new RuntimeException(">"+name+"<: invalid url: >"+parsed_url+"< should be: >"+request_url+"<"); } if (!fragment.equals(parsed_frag)) { throw new RuntimeException(name+": invalid fragement: "+parsed_frag+" should be: "+fragment); } if (null != currHValue || null != currHField) { if (null == currHField || null == currHValue) { throw new RuntimeException("shouldn't happen"); } } if (null != currHField) { //p(currHField); //p(">"+currHValue+"<"); parsed_header.put(currHField, currHValue); currHField = null; currHValue = null; } return 0; } }; // s.on_headers_complete = new HTTPCallback() { // public int cb (HTTPParser p) { // p("Complete:"+name); // return 0; // } // }; s.on_body = new HTTPDataCallback() { public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ int l = pbody == null ? len : len + pbody.length; int off = pbody == null ? 0 : pbody.length; byte [] nbody = new byte[l]; if (null != pbody) { System.arraycopy(pbody, 0, nbody, 0, pbody.length); } int saved = b.position(); b.position(pos); b.get(nbody, off, len); b.position(saved); pbody = nbody; return 0; } }; s.on_message_complete = new HTTPCallback() { public int cb(HTTPParser p) { message_complete_called = true; num_called += 1; if ( p.http_minor != http_minor || p.http_major != http_major || p.status_code != status_code ) { throw new RuntimeException("major/minor/status_code mismatch"); } //check headers if (header.keySet().size() != parsed_header.keySet().size()) { p(parsed_header); throw new RuntimeException(name+": different amount of headers"); } for (String key : header.keySet()) { String pvalue = parsed_header.get(key); if (!header.get(key).equals(pvalue)) { throw new RuntimeException(name+" : different values for :"+key+" is >"+pvalue+"< should: >"+header.get(key)+"<"); } } //check body if (null == pbody && (null == body || body.length == 0 || body.length == 1)) { s.success = true; return 0; } if (null == pbody) { throw new RuntimeException(name+": no body, should be: "+new String(body)); } if (pbody.length != body.length) { p(pbody.length); p(body.length); p(new String(pbody)); p(new String(body)); throw new RuntimeException(name+": incorrect body length"); } for (int i = 0 ; i!= body.length; ++i) { if (pbody[i] != body[i]) { throw new RuntimeException("different body"); } } s.success = true; return 0; } }; return s; } // settings static void p(Object o) { System.out.println(o); } static class TestSettings extends ParserSettings { public boolean success; Map<String, ByteList> map; TestSettings () { map = new HashMap<String, ByteList>(); map.put("path", new ByteList()); map.put("query_string", new ByteList()); map.put("url", new ByteList()); map.put("fragment", new ByteList()); } }
}