48 private String statusLine; |
48 private String statusLine; |
49 private int responseCode; |
49 private int responseCode; |
50 private HttpHeaders headers; |
50 private HttpHeaders headers; |
51 private Map<String,List<String>> privateMap = new HashMap<>(); |
51 private Map<String,List<String>> privateMap = new HashMap<>(); |
52 |
52 |
53 enum State { STATUS_LINE, |
53 enum State { INITIAL, |
|
54 STATUS_LINE, |
54 STATUS_LINE_FOUND_CR, |
55 STATUS_LINE_FOUND_CR, |
55 STATUS_LINE_FOUND_LF, |
56 STATUS_LINE_FOUND_LF, |
56 STATUS_LINE_END, |
57 STATUS_LINE_END, |
57 STATUS_LINE_END_CR, |
58 STATUS_LINE_END_CR, |
58 STATUS_LINE_END_LF, |
59 STATUS_LINE_END_LF, |
61 HEADER_FOUND_LF, |
62 HEADER_FOUND_LF, |
62 HEADER_FOUND_CR_LF, |
63 HEADER_FOUND_CR_LF, |
63 HEADER_FOUND_CR_LF_CR, |
64 HEADER_FOUND_CR_LF_CR, |
64 FINISHED } |
65 FINISHED } |
65 |
66 |
66 private State state = State.STATUS_LINE; |
67 private State state = State.INITIAL; |
67 |
68 |
68 /** Returns the status-line. */ |
69 /** Returns the status-line. */ |
69 String statusLine() { return statusLine; } |
70 String statusLine() { return statusLine; } |
70 |
71 |
71 /** Returns the response code. */ |
72 /** Returns the response code. */ |
73 |
74 |
74 /** Returns the headers, possibly empty. */ |
75 /** Returns the headers, possibly empty. */ |
75 HttpHeaders headers() { |
76 HttpHeaders headers() { |
76 assert state == State.FINISHED : "Unexpected state " + state; |
77 assert state == State.FINISHED : "Unexpected state " + state; |
77 return headers; |
78 return headers; |
|
79 } |
|
80 |
|
81 /** A current-state message suitable for inclusion in an exception detail message. */ |
|
82 public String currentStateMessage() { |
|
83 String stateName = state.name(); |
|
84 String msg; |
|
85 if (stateName.contains("INITIAL")) { |
|
86 return format("HTTP/1.1 header parser received no bytes"); |
|
87 } else if (stateName.contains("STATUS")) { |
|
88 msg = format("parsing HTTP/1.1 status line, receiving [%s]", sb.toString()); |
|
89 } else if (stateName.contains("HEADER")) { |
|
90 String headerName = sb.toString(); |
|
91 if (headerName.indexOf(':') != -1) |
|
92 headerName = headerName.substring(0, headerName.indexOf(':')+1) + "..."; |
|
93 msg = format("parsing HTTP/1.1 header, receiving [%s]", headerName); |
|
94 } else { |
|
95 msg =format("HTTP/1.1 parser receiving [%s]", state, sb.toString()); |
|
96 } |
|
97 return format("%s, parser state [%s]", msg , state); |
78 } |
98 } |
79 |
99 |
80 /** |
100 /** |
81 * Parses HTTP/1.X status-line and headers from the given bytes. Must be |
101 * Parses HTTP/1.X status-line and headers from the given bytes. Must be |
82 * called successive times, with additional data, until returns true. |
102 * called successive times, with additional data, until returns true. |
90 boolean parse(ByteBuffer input) throws ProtocolException { |
110 boolean parse(ByteBuffer input) throws ProtocolException { |
91 requireNonNull(input, "null input"); |
111 requireNonNull(input, "null input"); |
92 |
112 |
93 while (canContinueParsing(input)) { |
113 while (canContinueParsing(input)) { |
94 switch (state) { |
114 switch (state) { |
|
115 case INITIAL: |
|
116 state = State.STATUS_LINE; |
|
117 break; |
95 case STATUS_LINE: |
118 case STATUS_LINE: |
96 readResumeStatusLine(input); |
119 readResumeStatusLine(input); |
97 break; |
120 break; |
98 // fallthrough |
121 // fallthrough |
99 case STATUS_LINE_FOUND_CR: |
122 case STATUS_LINE_FOUND_CR: |