3535 */
3636class Request {
3737
38- static final int BUF_LEN = 2048 ;
39- static final byte CR = 13 ;
40- static final byte LF = 10 ;
38+ static final char CR = 13 ;
39+ static final char LF = 10 ;
4140
4241 private String startLine ;
43- private InputStream is ;
44- private OutputStream os ;
42+ private final InputStream is ;
43+ private final OutputStream os ;
4544
4645 Request (InputStream rawInputStream , OutputStream rawout ) throws IOException {
4746 is = rawInputStream ;
@@ -52,10 +51,6 @@ class Request {
5251 } while ("" .equals (startLine ));
5352 }
5453
55- char [] buf = new char [BUF_LEN ];
56- int pos ;
57- StringBuffer lineBuf ;
58-
5954 public InputStream inputStream () {
6055 return is ;
6156 }
@@ -64,22 +59,73 @@ public OutputStream outputStream() {
6459 return os ;
6560 }
6661
62+ static class PushbackStream {
63+ private final InputStream is ;
64+ private int pushback = -1 ;
65+ private boolean eof =false ;
66+
67+ public PushbackStream (InputStream is ) {
68+ this .is = is ;
69+ }
70+ public int read () throws IOException {
71+ if (pushback !=-1 ) {
72+ try {
73+ return pushback ;
74+ } finally {
75+ pushback =-1 ;
76+ }
77+ }
78+ if (eof ) return -1 ;
79+ return is .read ();
80+ }
81+ public void skipWhitespace () throws IOException {
82+ int c ;
83+ for (c =read ();c ==' ' || c =='\t' ;c =read ()){}
84+ if (c ==-1 ) eof =true ; else pushback =c ;
85+ }
86+ }
87+
88+ // efficient building of trimmed strings
89+ static class StrBuilder {
90+ private char buffer [] = new char [128 ];
91+ private int count =0 ;
92+ public void append (int c ) {
93+ if (count ==0 && c ==' ' ) return ;
94+ if (count ==buffer .length ) {
95+ char tmp [] = new char [buffer .length *2 ];
96+ System .arraycopy (buffer ,0 ,tmp ,0 ,count );
97+ buffer =tmp ;
98+ }
99+ buffer [count ++]=(char )c ;
100+ }
101+ @ Override
102+ public String toString () {
103+ while (count >0 && buffer [count -1 ]==' ' ) count --;
104+ return new String (buffer ,0 ,count );
105+ }
106+ public boolean isEmpty () {
107+ return count ==0 ;
108+ }
109+ public void clear () {
110+ count =0 ;
111+ }
112+ }
113+
67114 /**
68115 * read a line from the stream returning as a String.
69116 * Not used for reading headers.
70117 */
118+ private String readLine () throws IOException {
119+ StringBuilder lineBuf = new StringBuilder ();
71120
72- public String readLine () throws IOException {
73- boolean gotCR = false , gotLF = false ;
74- pos = 0 ;
75- lineBuf = new StringBuffer ();
76- while (!gotLF ) {
121+ boolean gotCR = false ;
122+ while (true ) {
77123 int c ;
78124
79125 try {
80126 c = is .read ();
81127 } catch (IOException e ) {
82- if (pos ==0 ) return null ;
128+ if (lineBuf . length () ==0 ) return null ;
83129 throw e ;
84130 }
85131
@@ -88,30 +134,20 @@ public String readLine() throws IOException {
88134 }
89135 if (gotCR ) {
90136 if (c == LF ) {
91- gotLF = true ;
137+ return new String ( lineBuf ) ;
92138 } else {
93139 gotCR = false ;
94- consume (CR );
95- consume ( c );
140+ lineBuf . append (CR );
141+ lineBuf . append (( char ) c );
96142 }
97143 } else {
98144 if (c == CR ) {
99145 gotCR = true ;
100146 } else {
101- consume ( c );
147+ lineBuf . append (( char ) c );
102148 }
103149 }
104150 }
105- lineBuf .append (buf , 0 , pos );
106- return new String (lineBuf );
107- }
108-
109- private void consume (int c ) {
110- if (pos == BUF_LEN ) {
111- lineBuf .append (buf );
112- pos = 0 ;
113- }
114- buf [pos ++] = (char ) c ;
115151 }
116152
117153 /**
@@ -130,91 +166,49 @@ Headers headers() throws IOException {
130166 }
131167 hdrs = new Headers ();
132168
133- char s [] = new char [ 10 ] ;
134- int len = 0 ;
169+ StrBuilder key = new StrBuilder () ;
170+ StrBuilder value = new StrBuilder () ;
135171
136- int firstc = is . read ( );
172+ PushbackStream pbs = new PushbackStream ( is );
137173
138- // check for empty headers
139- if (firstc == CR || firstc == LF ) {
140- int c = is .read ();
141- if (c == CR || c == LF ) {
142- return hdrs ;
143- }
144- s [0 ] = (char ) firstc ;
145- len = 1 ;
146- firstc = c ;
147- }
174+ boolean inKey = true ;
175+ boolean prevCR = false ;
176+ boolean sol = true ;
177+ int c ;
148178
149- while (firstc != LF && firstc != CR && firstc >= 0 ) {
150- int keyend = -1 ;
151- int c ;
152- boolean inKey = firstc > ' ' ;
153- s [len ++] = (char ) firstc ;
154- parseloop : {
155- while ((c = is .read ()) >= 0 ) {
156- switch (c ) {
157- /* fallthrough */
158- case ':' :
159- if (inKey && len > 0 )
160- keyend = len ;
161- inKey = false ;
162- break ;
163- case '\t' :
164- c = ' ' ;
165- case ' ' :
166- inKey = false ;
167- break ;
168- case CR :
169- case LF :
170- firstc = is .read ();
171- if (c == CR && firstc == LF ) {
172- firstc = is .read ();
173- if (firstc == CR )
174- firstc = is .read ();
175- }
176- if (firstc == LF || firstc == CR || firstc > ' ' )
177- break parseloop ;
178- /* continuation */
179- c = ' ' ;
180- break ;
179+ while ((c =pbs .read ())!=-1 ) {
180+ if (c ==CR ) { prevCR = true ; }
181+ else if (c ==LF && prevCR ) {
182+ if (key .isEmpty () && value .isEmpty ()) break ;
183+ if (sol ) {
184+ hdrs .add (key .toString (),value .toString ());
185+ break ;
186+ }
187+ prevCR =false ;
188+ sol =true ;
189+ } else {
190+ if ((c ==' ' || c =='\t' ) && sol ) {
191+ pbs .skipWhitespace ();
192+ inKey =false ;
193+ sol =false ;
194+ } else {
195+ if (sol ) {
196+ if (!key .isEmpty () || !value .isEmpty ()) {
197+ hdrs .add (key .toString (),value .toString ());
198+ key .clear ();
199+ value .clear ();
200+ }
201+ inKey =true ;
202+ sol =false ;
181203 }
182- if (len >= s .length ) {
183- char ns [] = new char [s .length * 2 ];
184- System .arraycopy (s , 0 , ns , 0 , len );
185- s = ns ;
204+ if (c ==':' && inKey ) {
205+ inKey =false ;
206+ pbs .skipWhitespace ();
207+ } else {
208+ (inKey ? key : value ).append (c );
186209 }
187- s [len ++] = (char ) c ;
188210 }
189- firstc = -1 ;
190- }
191- while (len > 0 && s [len - 1 ] <= ' ' )
192- len --;
193- String k ;
194- if (keyend <= 0 ) {
195- k = null ;
196- keyend = 0 ;
197- } else {
198- k = String .copyValueOf (s , 0 , keyend );
199- if (keyend < len && s [keyend ] == ':' )
200- keyend ++;
201- while (keyend < len && s [keyend ] <= ' ' )
202- keyend ++;
203- }
204- String v ;
205- if (keyend >= len )
206- v = new String ();
207- else
208- v = String .copyValueOf (s , keyend , len - keyend );
209-
210- if (hdrs .size () >= ServerConfig .getMaxReqHeaders ()) {
211- throw new IOException ("maximum number of headers exceeded" );
212- }
213- if (k == null ) { // Headers disallows null keys, use empty string
214- k = "" ; // instead to represent invalid key
215211 }
216- hdrs .add (k , v );
217- len = 0 ;
218212 }
219213 return hdrs ;
220214 }
0 commit comments