1
17 package org.apache.coyote;
18
19 import java.io.IOException;
20 import java.io.UnsupportedEncodingException;
21 import java.nio.charset.Charset;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.concurrent.atomic.AtomicBoolean;
25
26 import javax.servlet.ReadListener;
27
28 import org.apache.tomcat.util.buf.B2CConverter;
29 import org.apache.tomcat.util.buf.MessageBytes;
30 import org.apache.tomcat.util.buf.UDecoder;
31 import org.apache.tomcat.util.http.MimeHeaders;
32 import org.apache.tomcat.util.http.Parameters;
33 import org.apache.tomcat.util.http.ServerCookies;
34 import org.apache.tomcat.util.net.ApplicationBufferHandler;
35 import org.apache.tomcat.util.res.StringManager;
36
37
64 public final class Request {
65
66 private static final StringManager sm = StringManager.getManager(Request.class);
67
68
69 private static final int INITIAL_COOKIE_SIZE = 4;
70
71
72
73 public Request() {
74 parameters.setQuery(queryMB);
75 parameters.setURLDecoder(urlDecoder);
76 }
77
78
79
80
81 private int serverPort = -1;
82 private final MessageBytes serverNameMB = MessageBytes.newInstance();
83
84 private int remotePort;
85 private int localPort;
86
87 private final MessageBytes schemeMB = MessageBytes.newInstance();
88
89 private final MessageBytes methodMB = MessageBytes.newInstance();
90 private final MessageBytes uriMB = MessageBytes.newInstance();
91 private final MessageBytes decodedUriMB = MessageBytes.newInstance();
92 private final MessageBytes queryMB = MessageBytes.newInstance();
93 private final MessageBytes protoMB = MessageBytes.newInstance();
94
95
96 private final MessageBytes remoteAddrMB = MessageBytes.newInstance();
97 private final MessageBytes localNameMB = MessageBytes.newInstance();
98 private final MessageBytes remoteHostMB = MessageBytes.newInstance();
99 private final MessageBytes localAddrMB = MessageBytes.newInstance();
100
101 private final MimeHeaders headers = new MimeHeaders();
102 private final Map<String,String> trailerFields = new HashMap<>();
103
104
105
108 private final Map<String,String> pathParameters = new HashMap<>();
109
110
113 private final Object notes[] = new Object[Constants.MAX_NOTES];
114
115
116
119 private InputBuffer inputBuffer = null;
120
121
122
125 private final UDecoder urlDecoder = new UDecoder();
126
127
128
131 private long contentLength = -1;
132 private MessageBytes contentTypeMB = null;
133 private Charset charset = null;
134
135
136 private String characterEncoding = null;
137
138
141 private boolean expectation = false;
142
143 private final ServerCookies serverCookies = new ServerCookies(INITIAL_COOKIE_SIZE);
144 private final Parameters parameters = new Parameters();
145
146 private final MessageBytes remoteUser = MessageBytes.newInstance();
147 private boolean remoteUserNeedsAuthorization = false;
148 private final MessageBytes authType = MessageBytes.newInstance();
149 private final HashMap<String,Object> attributes = new HashMap<>();
150
151 private Response response;
152 private volatile ActionHook hook;
153
154 private long bytesRead=0;
155
156 private long startTime = -1;
157 private int available = 0;
158
159 private final RequestInfo reqProcessorMX=new RequestInfo(this);
160
161 private boolean sendfile = true;
162
163 volatile ReadListener listener;
164
165 public ReadListener getReadListener() {
166 return listener;
167 }
168
169 public void setReadListener(ReadListener listener) {
170 if (listener == null) {
171 throw new NullPointerException(
172 sm.getString("request.nullReadListener"));
173 }
174 if (getReadListener() != null) {
175 throw new IllegalStateException(
176 sm.getString("request.readListenerSet"));
177 }
178
179
180 AtomicBoolean result = new AtomicBoolean(false);
181 action(ActionCode.ASYNC_IS_ASYNC, result);
182 if (!result.get()) {
183 throw new IllegalStateException(
184 sm.getString("request.notAsync"));
185 }
186
187 this.listener = listener;
188 }
189
190 private final AtomicBoolean allDataReadEventSent = new AtomicBoolean(false);
191
192 public boolean sendAllDataReadEvent() {
193 return allDataReadEventSent.compareAndSet(false, true);
194 }
195
196
197
198
199 public MimeHeaders getMimeHeaders() {
200 return headers;
201 }
202
203
204 public boolean isTrailerFieldsReady() {
205 AtomicBoolean result = new AtomicBoolean(false);
206 action(ActionCode.IS_TRAILER_FIELDS_READY, result);
207 return result.get();
208 }
209
210
211 public Map<String,String> getTrailerFields() {
212 return trailerFields;
213 }
214
215
216 public UDecoder getURLDecoder() {
217 return urlDecoder;
218 }
219
220
221
222
223 public MessageBytes scheme() {
224 return schemeMB;
225 }
226
227 public MessageBytes method() {
228 return methodMB;
229 }
230
231 public MessageBytes requestURI() {
232 return uriMB;
233 }
234
235 public MessageBytes decodedURI() {
236 return decodedUriMB;
237 }
238
239 public MessageBytes queryString() {
240 return queryMB;
241 }
242
243 public MessageBytes protocol() {
244 return protoMB;
245 }
246
247
254 public MessageBytes serverName() {
255 return serverNameMB;
256 }
257
258 public int getServerPort() {
259 return serverPort;
260 }
261
262 public void setServerPort(int serverPort ) {
263 this.serverPort=serverPort;
264 }
265
266 public MessageBytes remoteAddr() {
267 return remoteAddrMB;
268 }
269
270 public MessageBytes remoteHost() {
271 return remoteHostMB;
272 }
273
274 public MessageBytes localName() {
275 return localNameMB;
276 }
277
278 public MessageBytes localAddr() {
279 return localAddrMB;
280 }
281
282 public int getRemotePort(){
283 return remotePort;
284 }
285
286 public void setRemotePort(int port){
287 this.remotePort = port;
288 }
289
290 public int getLocalPort(){
291 return localPort;
292 }
293
294 public void setLocalPort(int port){
295 this.localPort = port;
296 }
297
298
299
300
301
308 public String getCharacterEncoding() {
309 if (characterEncoding == null) {
310 characterEncoding = getCharsetFromContentType(getContentType());
311 }
312
313 return characterEncoding;
314 }
315
316
317
327 public Charset getCharset() throws UnsupportedEncodingException {
328 if (charset == null) {
329 getCharacterEncoding();
330 if (characterEncoding != null) {
331 charset = B2CConverter.getCharset(characterEncoding);
332 }
333 }
334
335 return charset;
336 }
337
338
339 public void setCharset(Charset charset) {
340 this.charset = charset;
341 this.characterEncoding = charset.name();
342 }
343
344
345 public void setContentLength(long len) {
346 this.contentLength = len;
347 }
348
349
350 public int getContentLength() {
351 long length = getContentLengthLong();
352
353 if (length < Integer.MAX_VALUE) {
354 return (int) length;
355 }
356 return -1;
357 }
358
359 public long getContentLengthLong() {
360 if( contentLength > -1 ) {
361 return contentLength;
362 }
363
364 MessageBytes clB = headers.getUniqueValue("content-length");
365 contentLength = (clB == null || clB.isNull()) ? -1 : clB.getLong();
366
367 return contentLength;
368 }
369
370 public String getContentType() {
371 contentType();
372 if ((contentTypeMB == null) || contentTypeMB.isNull()) {
373 return null;
374 }
375 return contentTypeMB.toString();
376 }
377
378
379 public void setContentType(String type) {
380 contentTypeMB.setString(type);
381 }
382
383
384 public MessageBytes contentType() {
385 if (contentTypeMB == null) {
386 contentTypeMB = headers.getValue("content-type");
387 }
388 return contentTypeMB;
389 }
390
391
392 public void setContentType(MessageBytes mb) {
393 contentTypeMB=mb;
394 }
395
396
397 public String getHeader(String name) {
398 return headers.getHeader(name);
399 }
400
401
402 public void setExpectation(boolean expectation) {
403 this.expectation = expectation;
404 }
405
406
407 public boolean hasExpectation() {
408 return expectation;
409 }
410
411
412
413
414 public Response getResponse() {
415 return response;
416 }
417
418 public void setResponse(Response response) {
419 this.response = response;
420 response.setRequest(this);
421 }
422
423 protected void setHook(ActionHook hook) {
424 this.hook = hook;
425 }
426
427 public void action(ActionCode actionCode, Object param) {
428 if (hook != null) {
429 if (param == null) {
430 hook.action(actionCode, this);
431 } else {
432 hook.action(actionCode, param);
433 }
434 }
435 }
436
437
438
439
440 public ServerCookies getCookies() {
441 return serverCookies;
442 }
443
444
445
446
447 public Parameters getParameters() {
448 return parameters;
449 }
450
451
452 public void addPathParameter(String name, String value) {
453 pathParameters.put(name, value);
454 }
455
456 public String getPathParameter(String name) {
457 return pathParameters.get(name);
458 }
459
460
461
462
463
464 public void setAttribute( String name, Object o ) {
465 attributes.put( name, o );
466 }
467
468 public HashMap<String,Object> getAttributes() {
469 return attributes;
470 }
471
472 public Object getAttribute(String name ) {
473 return attributes.get(name);
474 }
475
476 public MessageBytes getRemoteUser() {
477 return remoteUser;
478 }
479
480 public boolean getRemoteUserNeedsAuthorization() {
481 return remoteUserNeedsAuthorization;
482 }
483
484 public void setRemoteUserNeedsAuthorization(boolean remoteUserNeedsAuthorization) {
485 this.remoteUserNeedsAuthorization = remoteUserNeedsAuthorization;
486 }
487
488 public MessageBytes getAuthType() {
489 return authType;
490 }
491
492 public int getAvailable() {
493 return available;
494 }
495
496 public void setAvailable(int available) {
497 this.available = available;
498 }
499
500 public boolean getSendfile() {
501 return sendfile;
502 }
503
504 public void setSendfile(boolean sendfile) {
505 this.sendfile = sendfile;
506 }
507
508 public boolean isFinished() {
509 AtomicBoolean result = new AtomicBoolean(false);
510 action(ActionCode.REQUEST_BODY_FULLY_READ, result);
511 return result.get();
512 }
513
514 public boolean getSupportsRelativeRedirects() {
515 if (protocol().equals("") || protocol().equals("HTTP/1.0")) {
516 return false;
517 }
518 return true;
519 }
520
521
522
523
524 public InputBuffer getInputBuffer() {
525 return inputBuffer;
526 }
527
528
529 public void setInputBuffer(InputBuffer inputBuffer) {
530 this.inputBuffer = inputBuffer;
531 }
532
533
534
550 public int doRead(ApplicationBufferHandler handler) throws IOException {
551 int n = inputBuffer.doRead(handler);
552 if (n > 0) {
553 bytesRead+=n;
554 }
555 return n;
556 }
557
558
559
560
561 @Override
562 public String toString() {
563 return "R( " + requestURI().toString() + ")";
564 }
565
566 public long getStartTime() {
567 return startTime;
568 }
569
570 public void setStartTime(long startTime) {
571 this.startTime = startTime;
572 }
573
574
575
576
577
595 public final void setNote(int pos, Object value) {
596 notes[pos] = value;
597 }
598
599
600 public final Object getNote(int pos) {
601 return notes[pos];
602 }
603
604
605
606
607
608 public void recycle() {
609 bytesRead=0;
610
611 contentLength = -1;
612 contentTypeMB = null;
613 charset = null;
614 characterEncoding = null;
615 expectation = false;
616 headers.recycle();
617 trailerFields.clear();
618 serverNameMB.recycle();
619 serverPort=-1;
620 localAddrMB.recycle();
621 localNameMB.recycle();
622 localPort = -1;
623 remoteAddrMB.recycle();
624 remoteHostMB.recycle();
625 remotePort = -1;
626 available = 0;
627 sendfile = true;
628
629 serverCookies.recycle();
630 parameters.recycle();
631 pathParameters.clear();
632
633 uriMB.recycle();
634 decodedUriMB.recycle();
635 queryMB.recycle();
636 methodMB.recycle();
637 protoMB.recycle();
638
639 schemeMB.recycle();
640
641 remoteUser.recycle();
642 remoteUserNeedsAuthorization = false;
643 authType.recycle();
644 attributes.clear();
645
646 listener = null;
647 allDataReadEventSent.set(false);
648
649 startTime = -1;
650 }
651
652
653 public void updateCounters() {
654 reqProcessorMX.updateCounters();
655 }
656
657 public RequestInfo getRequestProcessor() {
658 return reqProcessorMX;
659 }
660
661 public long getBytesRead() {
662 return bytesRead;
663 }
664
665 public boolean isProcessing() {
666 return reqProcessorMX.getStage()==org.apache.coyote.Constants.STAGE_SERVICE;
667 }
668
669
676 private static String getCharsetFromContentType(String contentType) {
677
678 if (contentType == null) {
679 return null;
680 }
681 int start = contentType.indexOf("charset=");
682 if (start < 0) {
683 return null;
684 }
685 String encoding = contentType.substring(start + 8);
686 int end = encoding.indexOf(';');
687 if (end >= 0) {
688 encoding = encoding.substring(0, end);
689 }
690 encoding = encoding.trim();
691 if ((encoding.length() > 2) && (encoding.startsWith("\""))
692 && (encoding.endsWith("\""))) {
693 encoding = encoding.substring(1, encoding.length() - 1);
694 }
695
696 return encoding.trim();
697 }
698 }
699