~ubuntu-branches/ubuntu/oneiric/tomcat7/oneiric-updates

« back to all changes in this revision

Viewing changes to java/org/apache/coyote/ajp/AbstractAjpProcessor.java

  • Committer: Bazaar Package Importer
  • Author(s): tony mancill
  • Date: 2011-07-25 22:58:33 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110725225833-1t773ak3y3g9utm2
Tags: 7.0.19-1
* Team upload.
* New upstream release.
  - Includes fix for CVE-2011-2526 (Closes: #634992)
* Remove patch for CVE-2011-2204 (included upstream).

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 *  See the License for the specific language governing permissions and
15
15
 *  limitations under the License.
16
16
 */
17
 
 
18
17
package org.apache.coyote.ajp;
19
18
 
20
19
import java.io.ByteArrayInputStream;
21
20
import java.io.IOException;
 
21
import java.io.InterruptedIOException;
22
22
import java.net.InetAddress;
23
23
import java.security.NoSuchProviderException;
24
24
import java.security.cert.CertificateFactory;
27
27
 
28
28
import org.apache.coyote.AbstractProcessor;
29
29
import org.apache.coyote.ActionCode;
30
 
import org.apache.coyote.Adapter;
31
30
import org.apache.coyote.AsyncContextCallback;
32
 
import org.apache.coyote.AsyncStateMachine;
33
31
import org.apache.coyote.InputBuffer;
34
32
import org.apache.coyote.Request;
 
33
import org.apache.coyote.RequestInfo;
35
34
import org.apache.juli.logging.Log;
 
35
import org.apache.tomcat.util.ExceptionUtils;
36
36
import org.apache.tomcat.util.buf.ByteChunk;
37
37
import org.apache.tomcat.util.buf.HexUtils;
38
38
import org.apache.tomcat.util.buf.MessageBytes;
39
39
import org.apache.tomcat.util.http.HttpMessages;
40
40
import org.apache.tomcat.util.http.MimeHeaders;
 
41
import org.apache.tomcat.util.net.AbstractEndpoint;
41
42
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
42
43
import org.apache.tomcat.util.net.SSLSupport;
 
44
import org.apache.tomcat.util.net.SocketStatus;
43
45
import org.apache.tomcat.util.res.StringManager;
44
46
 
45
47
/**
46
48
 * Base class for AJP Processor implementations.
47
49
 */
48
 
public abstract class AbstractAjpProcessor extends AbstractProcessor {
 
50
public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> {
49
51
 
50
52
    protected abstract Log getLog();
51
53
 
 
54
 
52
55
    /**
53
56
     * The string manager for this package.
54
57
     */
55
58
    protected static final StringManager sm =
56
59
        StringManager.getManager(Constants.Package);
57
60
 
 
61
 
 
62
    /**
 
63
     * End message array.
 
64
     */
 
65
    protected static final byte[] endMessageArray;
 
66
 
 
67
 
 
68
    /**
 
69
     * Flush message array.
 
70
     */
 
71
    protected static final byte[] flushMessageArray;
 
72
 
 
73
 
 
74
    /**
 
75
     * Pong message array.
 
76
     */
 
77
    protected static final byte[] pongMessageArray;
 
78
 
 
79
 
 
80
    static {
 
81
        // Allocate the end message array
 
82
        AjpMessage endMessage = new AjpMessage(16);
 
83
        endMessage.reset();
 
84
        endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE);
 
85
        endMessage.appendByte(1);
 
86
        endMessage.end();
 
87
        endMessageArray = new byte[endMessage.getLen()];
 
88
        System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0,
 
89
                endMessage.getLen());
 
90
 
 
91
        // Allocate the flush message array
 
92
        AjpMessage flushMessage = new AjpMessage(16);
 
93
        flushMessage.reset();
 
94
        flushMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
 
95
        flushMessage.appendInt(0);
 
96
        flushMessage.appendByte(0);
 
97
        flushMessage.end();
 
98
        flushMessageArray = new byte[flushMessage.getLen()];
 
99
        System.arraycopy(flushMessage.getBuffer(), 0, flushMessageArray, 0,
 
100
                flushMessage.getLen());
 
101
 
 
102
        // Allocate the pong message array
 
103
        AjpMessage pongMessage = new AjpMessage(16);
 
104
        pongMessage.reset();
 
105
        pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY);
 
106
        pongMessage.end();
 
107
        pongMessageArray = new byte[pongMessage.getLen()];
 
108
        System.arraycopy(pongMessage.getBuffer(), 0, pongMessageArray, 
 
109
                0, pongMessage.getLen());
 
110
    }
 
111
 
 
112
 
58
113
    // ----------------------------------------------------- Instance Variables
59
114
 
60
115
 
61
116
    /**
62
 
     * Associated adapter.
 
117
     * GetBody message array. Not static like the other message arrays since the
 
118
     * message varies with packetSize and that can vary per connector.
63
119
     */
64
 
    protected Adapter adapter = null;
 
120
    protected final byte[] getBodyMessageArray;
65
121
 
66
122
 
67
123
    /**
89
145
     */
90
146
    protected AjpMessage bodyMessage = null;
91
147
 
92
 
    
 
148
 
93
149
    /**
94
150
     * Body message.
95
151
     */
148
204
     * Finished response.
149
205
     */
150
206
    protected boolean finished = false;
151
 
    
152
 
    
153
 
    /**
154
 
     * Track changes in state for async requests.
155
 
     */
156
 
    protected AsyncStateMachine asyncStateMachine = new AsyncStateMachine(this);
157
207
 
158
208
 
159
209
    /**
160
210
     * Bytes written to client for the current request
161
211
     */
162
212
    protected long byteCount = 0;
163
 
    
164
 
    
 
213
 
 
214
 
 
215
    // ------------------------------------------------------------ Constructor
 
216
 
 
217
    public AbstractAjpProcessor(int packetSize, AbstractEndpoint endpoint) {
 
218
 
 
219
        super(endpoint);
 
220
 
 
221
        this.packetSize = packetSize;
 
222
 
 
223
        request.setInputBuffer(new SocketInputBuffer());
 
224
 
 
225
        requestHeaderMessage = new AjpMessage(packetSize);
 
226
        responseHeaderMessage = new AjpMessage(packetSize);
 
227
        bodyMessage = new AjpMessage(packetSize);
 
228
 
 
229
        // Set the getBody message buffer
 
230
        AjpMessage getBodyMessage = new AjpMessage(16);
 
231
        getBodyMessage.reset();
 
232
        getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK);
 
233
        // Adjust read size if packetSize != default (Constants.MAX_PACKET_SIZE)
 
234
        getBodyMessage.appendInt(Constants.MAX_READ_SIZE + packetSize -
 
235
                Constants.MAX_PACKET_SIZE);
 
236
        getBodyMessage.end();
 
237
        getBodyMessageArray = new byte[getBodyMessage.getLen()];
 
238
        System.arraycopy(getBodyMessage.getBuffer(), 0, getBodyMessageArray, 
 
239
                0, getBodyMessage.getLen());
 
240
    }
 
241
 
 
242
 
165
243
    // ------------------------------------------------------------- Properties
166
244
 
167
245
 
210
288
    // --------------------------------------------------------- Public Methods
211
289
 
212
290
 
213
 
   /**
214
 
    * Send an action to the connector.
215
 
    *
216
 
    * @param actionCode Type of the action
217
 
    * @param param Action parameter
218
 
    */
219
 
   @Override
220
 
   public final void action(ActionCode actionCode, Object param) {
221
 
       
222
 
       if (actionCode == ActionCode.COMMIT) {
223
 
 
224
 
           if (response.isCommitted())
225
 
               return;
226
 
 
227
 
           // Validate and write response headers
228
 
           try {
229
 
               prepareResponse();
230
 
           } catch (IOException e) {
231
 
               // Set error flag
232
 
               error = true;
233
 
           }
234
 
 
235
 
           try {
236
 
               flush(false);
237
 
           } catch (IOException e) {
238
 
               // Set error flag
239
 
               error = true;
240
 
           }
241
 
 
242
 
       } else if (actionCode == ActionCode.CLIENT_FLUSH) {
243
 
 
244
 
           if (!response.isCommitted()) {
245
 
               // Validate and write response headers
246
 
               try {
247
 
                   prepareResponse();
248
 
               } catch (IOException e) {
249
 
                   // Set error flag
250
 
                   error = true;
251
 
                   return;
252
 
               }
253
 
           }
254
 
 
255
 
           try {
256
 
               flush(true);
257
 
           } catch (IOException e) {
258
 
               // Set error flag
259
 
               error = true;
260
 
           }
261
 
 
262
 
       } else if (actionCode == ActionCode.DISABLE_SWALLOW_INPUT) {
263
 
           // TODO: Do not swallow request input but
264
 
           // make sure we are closing the connection
265
 
           error = true;
266
 
 
267
 
       } else if (actionCode == ActionCode.CLOSE) {
268
 
           // Close
269
 
           // End the processing of the current request, and stop any further
270
 
           // transactions with the client
271
 
 
272
 
           try {
273
 
               finish();
274
 
           } catch (IOException e) {
275
 
               // Set error flag
276
 
               error = true;
277
 
           }
278
 
 
279
 
       } else if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) {
280
 
 
281
 
           if (!certificates.isNull()) {
282
 
               ByteChunk certData = certificates.getByteChunk();
283
 
               X509Certificate jsseCerts[] = null;
284
 
               ByteArrayInputStream bais =
285
 
                   new ByteArrayInputStream(certData.getBytes(),
286
 
                           certData.getStart(),
287
 
                           certData.getLength());
288
 
               // Fill the  elements.
289
 
               try {
290
 
                   CertificateFactory cf;
291
 
                   if (clientCertProvider == null) {
292
 
                       cf = CertificateFactory.getInstance("X.509");
293
 
                   } else {
294
 
                       cf = CertificateFactory.getInstance("X.509",
295
 
                               clientCertProvider);
296
 
                   }
297
 
                   while(bais.available() > 0) {
298
 
                       X509Certificate cert = (X509Certificate)
299
 
                           cf.generateCertificate(bais);
300
 
                       if(jsseCerts == null) {
301
 
                           jsseCerts = new X509Certificate[1];
302
 
                           jsseCerts[0] = cert;
303
 
                       } else {
304
 
                           X509Certificate [] temp = new X509Certificate[jsseCerts.length+1];
305
 
                           System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length);
306
 
                           temp[jsseCerts.length] = cert;
307
 
                           jsseCerts = temp;
308
 
                       }
309
 
                   }
310
 
               } catch (java.security.cert.CertificateException e) {
311
 
                   getLog().error(sm.getString("ajpprocessor.certs.fail"), e);
312
 
                   return;
313
 
               } catch (NoSuchProviderException e) {
314
 
                   getLog().error(sm.getString("ajpprocessor.certs.fail"), e);
315
 
                   return;
316
 
               }
317
 
               request.setAttribute(SSLSupport.CERTIFICATE_KEY, jsseCerts);
318
 
           }
319
 
 
320
 
       } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) {
321
 
 
322
 
           // Get remote host name using a DNS resolution
323
 
           if (request.remoteHost().isNull()) {
324
 
               try {
325
 
                   request.remoteHost().setString(InetAddress.getByName
326
 
                           (request.remoteAddr().toString()).getHostName());
327
 
               } catch (IOException iex) {
328
 
                   // Ignore
329
 
               }
330
 
           }
331
 
 
332
 
       } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) {
333
 
 
334
 
           // Copy from local name for now, which should simply be an address
335
 
           request.localAddr().setString(request.localName().toString());
336
 
 
337
 
       } else if (actionCode == ActionCode.REQ_SET_BODY_REPLAY) {
338
 
 
339
 
           // Set the given bytes as the content
340
 
           ByteChunk bc = (ByteChunk) param;
341
 
           int length = bc.getLength();
342
 
           bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length);
343
 
           request.setContentLength(length);
344
 
           first = false;
345
 
           empty = false;
346
 
           replay = true;
347
 
 
348
 
       } else if (actionCode == ActionCode.ASYNC_START) {
349
 
           asyncStateMachine.asyncStart((AsyncContextCallback) param);
350
 
       } else if (actionCode == ActionCode.ASYNC_DISPATCHED) {
351
 
           asyncStateMachine.asyncDispatched();
352
 
       } else if (actionCode == ActionCode.ASYNC_TIMEOUT) {
353
 
           AtomicBoolean result = (AtomicBoolean) param;
354
 
           result.set(asyncStateMachine.asyncTimeout());
355
 
       } else if (actionCode == ActionCode.ASYNC_RUN) {
356
 
           asyncStateMachine.asyncRun((Runnable) param);
357
 
       } else if (actionCode == ActionCode.ASYNC_ERROR) {
358
 
           asyncStateMachine.asyncError();
359
 
       } else if (actionCode == ActionCode.ASYNC_IS_STARTED) {
360
 
           ((AtomicBoolean) param).set(asyncStateMachine.isAsyncStarted());
361
 
       } else if (actionCode == ActionCode.ASYNC_IS_DISPATCHING) {
362
 
           ((AtomicBoolean) param).set(asyncStateMachine.isAsyncDispatching());
363
 
       } else if (actionCode == ActionCode.ASYNC_IS_ASYNC) {
364
 
           ((AtomicBoolean) param).set(asyncStateMachine.isAsync());
365
 
       } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) {
366
 
           ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut());
367
 
       }  else {
368
 
           actionInternal(actionCode, param);
369
 
       }
370
 
   }
371
 
   
372
 
   // Methods called by action()
373
 
   protected abstract void actionInternal(ActionCode actionCode, Object param);
374
 
   protected abstract void flush(boolean tbd) throws IOException;
375
 
   protected abstract void finish() throws IOException;
376
 
   
377
 
   
378
 
   public void recycle() {
379
 
       asyncStateMachine.recycle();
380
 
 
381
 
       // Recycle Request object
382
 
       first = true;
383
 
       endOfStream = false;
384
 
       empty = true;
385
 
       replay = false;
386
 
       finished = false;
387
 
       request.recycle();
388
 
       response.recycle();
389
 
       certificates.recycle();
390
 
       byteCount = 0;
391
 
   }
392
 
   
393
 
   // ------------------------------------------------------ Connector Methods
394
 
 
395
 
 
396
 
   /**
397
 
    * Set the associated adapter.
398
 
    *
399
 
    * @param adapter the new adapter
400
 
    */
401
 
   public void setAdapter(Adapter adapter) {
402
 
       this.adapter = adapter;
403
 
   }
404
 
 
405
 
 
406
 
   /**
407
 
    * Get the associated adapter.
408
 
    *
409
 
    * @return the associated adapter
410
 
    */
411
 
   public Adapter getAdapter() {
412
 
       return adapter;
413
 
   }
414
 
   
415
 
   
416
 
   // ------------------------------------------------------ Protected Methods
417
 
 
418
 
 
419
 
   /**
420
 
    * After reading the request headers, we have to setup the request filters.
421
 
    */
422
 
   protected void prepareRequest() {
423
 
 
424
 
       // Translate the HTTP method code to a String.
425
 
       byte methodCode = requestHeaderMessage.getByte();
426
 
       if (methodCode != Constants.SC_M_JK_STORED) {
427
 
           String methodName = Constants.getMethodForCode(methodCode - 1);
428
 
           request.method().setString(methodName);
429
 
       }
430
 
 
431
 
       requestHeaderMessage.getBytes(request.protocol());
432
 
       requestHeaderMessage.getBytes(request.requestURI());
433
 
 
434
 
       requestHeaderMessage.getBytes(request.remoteAddr());
435
 
       requestHeaderMessage.getBytes(request.remoteHost());
436
 
       requestHeaderMessage.getBytes(request.localName());
437
 
       request.setLocalPort(requestHeaderMessage.getInt());
438
 
 
439
 
       boolean isSSL = requestHeaderMessage.getByte() != 0;
440
 
       if (isSSL) {
441
 
           request.scheme().setString("https");
442
 
       }
443
 
 
444
 
       // Decode headers
445
 
       MimeHeaders headers = request.getMimeHeaders();
446
 
 
447
 
       int hCount = requestHeaderMessage.getInt();
448
 
       for(int i = 0 ; i < hCount ; i++) {
449
 
           String hName = null;
450
 
 
451
 
           // Header names are encoded as either an integer code starting
452
 
           // with 0xA0, or as a normal string (in which case the first
453
 
           // two bytes are the length).
454
 
           int isc = requestHeaderMessage.peekInt();
455
 
           int hId = isc & 0xFF;
456
 
 
457
 
           MessageBytes vMB = null;
458
 
           isc &= 0xFF00;
459
 
           if(0xA000 == isc) {
460
 
               requestHeaderMessage.getInt(); // To advance the read position
461
 
               hName = Constants.getHeaderForCode(hId - 1);
462
 
               vMB = headers.addValue(hName);
463
 
           } else {
464
 
               // reset hId -- if the header currently being read
465
 
               // happens to be 7 or 8 bytes long, the code below
466
 
               // will think it's the content-type header or the
467
 
               // content-length header - SC_REQ_CONTENT_TYPE=7,
468
 
               // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
469
 
               // behaviour.  see bug 5861 for more information.
470
 
               hId = -1;
471
 
               requestHeaderMessage.getBytes(tmpMB);
472
 
               ByteChunk bc = tmpMB.getByteChunk();
473
 
               vMB = headers.addValue(bc.getBuffer(),
474
 
                       bc.getStart(), bc.getLength());
475
 
           }
476
 
 
477
 
           requestHeaderMessage.getBytes(vMB);
478
 
 
479
 
           if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
480
 
                   (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
481
 
               // just read the content-length header, so set it
482
 
               long cl = vMB.getLong();
483
 
               if(cl < Integer.MAX_VALUE)
484
 
                   request.setContentLength( (int)cl );
485
 
           } else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
486
 
                   (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
487
 
               // just read the content-type header, so set it
488
 
               ByteChunk bchunk = vMB.getByteChunk();
489
 
               request.contentType().setBytes(bchunk.getBytes(),
490
 
                       bchunk.getOffset(),
491
 
                       bchunk.getLength());
492
 
           }
493
 
       }
494
 
 
495
 
       // Decode extra attributes
496
 
       boolean secret = false;
497
 
       byte attributeCode;
498
 
       while ((attributeCode = requestHeaderMessage.getByte())
499
 
               != Constants.SC_A_ARE_DONE) {
500
 
 
501
 
           switch (attributeCode) {
502
 
 
503
 
           case Constants.SC_A_REQ_ATTRIBUTE :
504
 
               requestHeaderMessage.getBytes(tmpMB);
505
 
               String n = tmpMB.toString();
506
 
               requestHeaderMessage.getBytes(tmpMB);
507
 
               String v = tmpMB.toString();
508
 
               /*
509
 
                * AJP13 misses to forward the remotePort.
510
 
                * Allow the AJP connector to add this info via
511
 
                * a private request attribute.
512
 
                * We will accept the forwarded data as the remote port,
513
 
                * and remove it from the public list of request attributes.
514
 
                */
515
 
               if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) {
516
 
                   try {
517
 
                       request.setRemotePort(Integer.parseInt(v));
518
 
                   } catch (NumberFormatException nfe) {
519
 
                       // Ignore invalid value
520
 
                   }
521
 
               } else {
522
 
                   request.setAttribute(n, v );
523
 
               }
524
 
               break;
525
 
 
526
 
           case Constants.SC_A_CONTEXT :
527
 
               requestHeaderMessage.getBytes(tmpMB);
528
 
               // nothing
529
 
               break;
530
 
 
531
 
           case Constants.SC_A_SERVLET_PATH :
532
 
               requestHeaderMessage.getBytes(tmpMB);
533
 
               // nothing
534
 
               break;
535
 
 
536
 
           case Constants.SC_A_REMOTE_USER :
537
 
               if (tomcatAuthentication) {
538
 
                   // ignore server
539
 
                   requestHeaderMessage.getBytes(tmpMB);
540
 
               } else {
541
 
                   requestHeaderMessage.getBytes(request.getRemoteUser());
542
 
               }
543
 
               break;
544
 
 
545
 
           case Constants.SC_A_AUTH_TYPE :
546
 
               if (tomcatAuthentication) {
547
 
                   // ignore server
548
 
                   requestHeaderMessage.getBytes(tmpMB);
549
 
               } else {
550
 
                   requestHeaderMessage.getBytes(request.getAuthType());
551
 
               }
552
 
               break;
553
 
 
554
 
           case Constants.SC_A_QUERY_STRING :
555
 
               requestHeaderMessage.getBytes(request.queryString());
556
 
               break;
557
 
 
558
 
           case Constants.SC_A_JVM_ROUTE :
559
 
               requestHeaderMessage.getBytes(request.instanceId());
560
 
               break;
561
 
 
562
 
           case Constants.SC_A_SSL_CERT :
563
 
               request.scheme().setString("https");
564
 
               // SSL certificate extraction is lazy, moved to JkCoyoteHandler
565
 
               requestHeaderMessage.getBytes(certificates);
566
 
               break;
567
 
 
568
 
           case Constants.SC_A_SSL_CIPHER :
569
 
               request.scheme().setString("https");
570
 
               requestHeaderMessage.getBytes(tmpMB);
571
 
               request.setAttribute(SSLSupport.CIPHER_SUITE_KEY,
572
 
                                    tmpMB.toString());
573
 
               break;
574
 
 
575
 
           case Constants.SC_A_SSL_SESSION :
576
 
               request.scheme().setString("https");
577
 
               requestHeaderMessage.getBytes(tmpMB);
578
 
               request.setAttribute(SSLSupport.SESSION_ID_KEY,
579
 
                                    tmpMB.toString());
580
 
               break;
581
 
 
582
 
           case Constants.SC_A_SSL_KEY_SIZE :
583
 
               request.setAttribute(SSLSupport.KEY_SIZE_KEY,
584
 
                       Integer.valueOf(requestHeaderMessage.getInt()));
585
 
               break;
586
 
 
587
 
           case Constants.SC_A_STORED_METHOD:
588
 
               requestHeaderMessage.getBytes(request.method());
589
 
               break;
590
 
 
591
 
           case Constants.SC_A_SECRET:
592
 
               requestHeaderMessage.getBytes(tmpMB);
593
 
               if (requiredSecret != null) {
594
 
                   secret = true;
595
 
                   if (!tmpMB.equals(requiredSecret)) {
596
 
                       response.setStatus(403);
597
 
                       adapter.log(request, response, 0);
598
 
                       error = true;
599
 
                   }
600
 
               }
601
 
               break;
602
 
 
603
 
           default:
604
 
               // Ignore unknown attribute for backward compatibility
605
 
               break;
606
 
 
607
 
           }
608
 
 
609
 
       }
610
 
 
611
 
       // Check if secret was submitted if required
612
 
       if ((requiredSecret != null) && !secret) {
613
 
           response.setStatus(403);
614
 
           adapter.log(request, response, 0);
615
 
           error = true;
616
 
       }
617
 
 
618
 
       // Check for a full URI (including protocol://host:port/)
619
 
       ByteChunk uriBC = request.requestURI().getByteChunk();
620
 
       if (uriBC.startsWithIgnoreCase("http", 0)) {
621
 
 
622
 
           int pos = uriBC.indexOf("://", 0, 3, 4);
623
 
           int uriBCStart = uriBC.getStart();
624
 
           int slashPos = -1;
625
 
           if (pos != -1) {
626
 
               byte[] uriB = uriBC.getBytes();
627
 
               slashPos = uriBC.indexOf('/', pos + 3);
628
 
               if (slashPos == -1) {
629
 
                   slashPos = uriBC.getLength();
630
 
                   // Set URI as "/"
631
 
                   request.requestURI().setBytes
632
 
                       (uriB, uriBCStart + pos + 1, 1);
633
 
               } else {
634
 
                   request.requestURI().setBytes
635
 
                       (uriB, uriBCStart + slashPos,
636
 
                        uriBC.getLength() - slashPos);
637
 
               }
638
 
               MessageBytes hostMB = headers.setValue("host");
639
 
               hostMB.setBytes(uriB, uriBCStart + pos + 3,
640
 
                               slashPos - pos - 3);
641
 
           }
642
 
 
643
 
       }
644
 
 
645
 
       MessageBytes valueMB = request.getMimeHeaders().getValue("host");
646
 
       parseHost(valueMB);
647
 
 
648
 
   }
649
 
   
650
 
   
651
 
   /**
652
 
    * Parse host.
653
 
    */
654
 
   protected void parseHost(MessageBytes valueMB) {
655
 
 
656
 
       if (valueMB == null || valueMB.isNull()) {
657
 
           // HTTP/1.0
658
 
           request.setServerPort(request.getLocalPort());
659
 
           try {
660
 
               request.serverName().duplicate(request.localName());
661
 
           } catch (IOException e) {
662
 
               response.setStatus(400);
663
 
               adapter.log(request, response, 0);
664
 
               error = true;
665
 
           }
666
 
           return;
667
 
       }
668
 
 
669
 
       ByteChunk valueBC = valueMB.getByteChunk();
670
 
       byte[] valueB = valueBC.getBytes();
671
 
       int valueL = valueBC.getLength();
672
 
       int valueS = valueBC.getStart();
673
 
       int colonPos = -1;
674
 
       if (hostNameC.length < valueL) {
675
 
           hostNameC = new char[valueL];
676
 
       }
677
 
 
678
 
       boolean ipv6 = (valueB[valueS] == '[');
679
 
       boolean bracketClosed = false;
680
 
       for (int i = 0; i < valueL; i++) {
681
 
           char b = (char) valueB[i + valueS];
682
 
           hostNameC[i] = b;
683
 
           if (b == ']') {
684
 
               bracketClosed = true;
685
 
           } else if (b == ':') {
686
 
               if (!ipv6 || bracketClosed) {
687
 
                   colonPos = i;
688
 
                   break;
689
 
               }
690
 
           }
691
 
       }
692
 
 
693
 
       if (colonPos < 0) {
694
 
           if (request.scheme().equalsIgnoreCase("https")) {
695
 
               // 443 - Default HTTPS port
696
 
               request.setServerPort(443);
697
 
           } else {
698
 
               // 80 - Default HTTTP port
699
 
               request.setServerPort(80);
700
 
           }
701
 
           request.serverName().setChars(hostNameC, 0, valueL);
702
 
       } else {
703
 
 
704
 
           request.serverName().setChars(hostNameC, 0, colonPos);
705
 
 
706
 
           int port = 0;
707
 
           int mult = 1;
708
 
           for (int i = valueL - 1; i > colonPos; i--) {
709
 
               int charValue = HexUtils.getDec(valueB[i + valueS]);
710
 
               if (charValue == -1) {
711
 
                   // Invalid character
712
 
                   error = true;
713
 
                   // 400 - Bad request
714
 
                   response.setStatus(400);
715
 
                   adapter.log(request, response, 0);
716
 
                   break;
717
 
               }
718
 
               port = port + (charValue * mult);
719
 
               mult = 10 * mult;
720
 
           }
721
 
           request.setServerPort(port);
722
 
       }
723
 
   }
724
 
   
725
 
   
726
 
   /**
727
 
    * When committing the response, we have to validate the set of headers, as
728
 
    * well as setup the response filters.
729
 
    */
730
 
   protected void prepareResponse()
731
 
       throws IOException {
732
 
 
733
 
       response.setCommitted(true);
734
 
 
735
 
       responseHeaderMessage.reset();
736
 
       responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
737
 
 
738
 
       // HTTP header contents
739
 
       responseHeaderMessage.appendInt(response.getStatus());
740
 
       String message = null;
741
 
       if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER &&
742
 
               HttpMessages.isSafeInHttpHeader(response.getMessage())) {
743
 
           message = response.getMessage();
744
 
       }
745
 
       if (message == null){
746
 
           message = HttpMessages.getMessage(response.getStatus());
747
 
       }
748
 
       if (message == null) {
749
 
           // mod_jk + httpd 2.x fails with a null status message - bug 45026
750
 
           message = Integer.toString(response.getStatus());
751
 
       }
752
 
       tmpMB.setString(message);
753
 
       responseHeaderMessage.appendBytes(tmpMB);
754
 
 
755
 
       // Special headers
756
 
       MimeHeaders headers = response.getMimeHeaders();
757
 
       String contentType = response.getContentType();
758
 
       if (contentType != null) {
759
 
           headers.setValue("Content-Type").setString(contentType);
760
 
       }
761
 
       String contentLanguage = response.getContentLanguage();
762
 
       if (contentLanguage != null) {
763
 
           headers.setValue("Content-Language").setString(contentLanguage);
764
 
       }
765
 
       long contentLength = response.getContentLengthLong();
766
 
       if (contentLength >= 0) {
767
 
           headers.setValue("Content-Length").setLong(contentLength);
768
 
       }
769
 
 
770
 
       // Other headers
771
 
       int numHeaders = headers.size();
772
 
       responseHeaderMessage.appendInt(numHeaders);
773
 
       for (int i = 0; i < numHeaders; i++) {
774
 
           MessageBytes hN = headers.getName(i);
775
 
           int hC = Constants.getResponseAjpIndex(hN.toString());
776
 
           if (hC > 0) {
777
 
               responseHeaderMessage.appendInt(hC);
778
 
           }
779
 
           else {
780
 
               responseHeaderMessage.appendBytes(hN);
781
 
           }
782
 
           MessageBytes hV=headers.getValue(i);
783
 
           responseHeaderMessage.appendBytes(hV);
784
 
       }
785
 
 
786
 
       // Write to buffer
787
 
       responseHeaderMessage.end();
788
 
       output(responseHeaderMessage.getBuffer(), 0,
789
 
               responseHeaderMessage.getLen());
790
 
   }
791
 
   
792
 
   // Methods called by prepareResponse()
793
 
   protected abstract void output(byte[] src, int offset, int length)
794
 
           throws IOException;
795
 
   
796
 
   
797
 
   protected boolean isAsync() {
798
 
       return asyncStateMachine.isAsync();
799
 
   }
800
 
   
801
 
   protected SocketState asyncPostProcess() {
802
 
       return asyncStateMachine.asyncPostProcess();
803
 
   }
804
 
 
805
 
   // ------------------------------------- InputStreamInputBuffer Inner Class
806
 
 
807
 
 
808
 
   /**
809
 
    * This class is an input buffer which will read its data from an input
810
 
    * stream.
811
 
    */
812
 
   protected class SocketInputBuffer
813
 
       implements InputBuffer {
814
 
 
815
 
 
816
 
       /**
817
 
        * Read bytes into the specified chunk.
818
 
        */
819
 
       @Override
820
 
       public int doRead(ByteChunk chunk, Request req )
821
 
           throws IOException {
822
 
 
823
 
           if (endOfStream) {
824
 
               return -1;
825
 
           }
826
 
           if (first && req.getContentLengthLong() > 0) {
827
 
               // Handle special first-body-chunk
828
 
               if (!receive()) {
829
 
                   return 0;
830
 
               }
831
 
           } else if (empty) {
832
 
               if (!refillReadBuffer()) {
833
 
                   return -1;
834
 
               }
835
 
           }
836
 
           ByteChunk bc = bodyBytes.getByteChunk();
837
 
           chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength());
838
 
           empty = true;
839
 
           return chunk.getLength();
840
 
 
841
 
       }
842
 
 
843
 
   }
844
 
   
845
 
   // Methods used by SocketInputBuffer
846
 
   protected abstract boolean receive() throws IOException;
847
 
   protected abstract boolean refillReadBuffer() throws IOException;
 
291
    /**
 
292
     * Send an action to the connector.
 
293
     *
 
294
     * @param actionCode Type of the action
 
295
     * @param param Action parameter
 
296
     */
 
297
    @Override
 
298
    public final void action(ActionCode actionCode, Object param) {
 
299
 
 
300
        if (actionCode == ActionCode.COMMIT) {
 
301
 
 
302
            if (response.isCommitted())
 
303
                return;
 
304
 
 
305
            // Validate and write response headers
 
306
            try {
 
307
                prepareResponse();
 
308
            } catch (IOException e) {
 
309
                // Set error flag
 
310
                error = true;
 
311
            }
 
312
 
 
313
            try {
 
314
                flush(false);
 
315
            } catch (IOException e) {
 
316
                // Set error flag
 
317
                error = true;
 
318
            }
 
319
 
 
320
        } else if (actionCode == ActionCode.CLIENT_FLUSH) {
 
321
 
 
322
            if (!response.isCommitted()) {
 
323
                // Validate and write response headers
 
324
                try {
 
325
                    prepareResponse();
 
326
                } catch (IOException e) {
 
327
                    // Set error flag
 
328
                    error = true;
 
329
                    return;
 
330
                }
 
331
            }
 
332
 
 
333
            try {
 
334
                flush(true);
 
335
            } catch (IOException e) {
 
336
                // Set error flag
 
337
                error = true;
 
338
            }
 
339
 
 
340
        } else if (actionCode == ActionCode.DISABLE_SWALLOW_INPUT) {
 
341
            // TODO: Do not swallow request input but
 
342
            // make sure we are closing the connection
 
343
            error = true;
 
344
 
 
345
        } else if (actionCode == ActionCode.CLOSE) {
 
346
            // Close
 
347
            // End the processing of the current request, and stop any further
 
348
            // transactions with the client
 
349
 
 
350
            try {
 
351
                finish();
 
352
            } catch (IOException e) {
 
353
                // Set error flag
 
354
                error = true;
 
355
            }
 
356
 
 
357
        } else if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) {
 
358
 
 
359
            if (!certificates.isNull()) {
 
360
                ByteChunk certData = certificates.getByteChunk();
 
361
                X509Certificate jsseCerts[] = null;
 
362
                ByteArrayInputStream bais =
 
363
                    new ByteArrayInputStream(certData.getBytes(),
 
364
                            certData.getStart(),
 
365
                            certData.getLength());
 
366
                // Fill the  elements.
 
367
                try {
 
368
                    CertificateFactory cf;
 
369
                    if (clientCertProvider == null) {
 
370
                        cf = CertificateFactory.getInstance("X.509");
 
371
                    } else {
 
372
                        cf = CertificateFactory.getInstance("X.509",
 
373
                                clientCertProvider);
 
374
                    }
 
375
                    while(bais.available() > 0) {
 
376
                        X509Certificate cert = (X509Certificate)
 
377
                        cf.generateCertificate(bais);
 
378
                        if(jsseCerts == null) {
 
379
                            jsseCerts = new X509Certificate[1];
 
380
                            jsseCerts[0] = cert;
 
381
                        } else {
 
382
                            X509Certificate [] temp = new X509Certificate[jsseCerts.length+1];
 
383
                            System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length);
 
384
                            temp[jsseCerts.length] = cert;
 
385
                            jsseCerts = temp;
 
386
                        }
 
387
                    }
 
388
                } catch (java.security.cert.CertificateException e) {
 
389
                    getLog().error(sm.getString("ajpprocessor.certs.fail"), e);
 
390
                    return;
 
391
                } catch (NoSuchProviderException e) {
 
392
                    getLog().error(sm.getString("ajpprocessor.certs.fail"), e);
 
393
                    return;
 
394
                }
 
395
                request.setAttribute(SSLSupport.CERTIFICATE_KEY, jsseCerts);
 
396
            }
 
397
 
 
398
        } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) {
 
399
 
 
400
            // Get remote host name using a DNS resolution
 
401
            if (request.remoteHost().isNull()) {
 
402
                try {
 
403
                    request.remoteHost().setString(InetAddress.getByName
 
404
                            (request.remoteAddr().toString()).getHostName());
 
405
                } catch (IOException iex) {
 
406
                    // Ignore
 
407
                }
 
408
            }
 
409
 
 
410
        } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) {
 
411
 
 
412
            // Copy from local name for now, which should simply be an address
 
413
            request.localAddr().setString(request.localName().toString());
 
414
 
 
415
        } else if (actionCode == ActionCode.REQ_SET_BODY_REPLAY) {
 
416
 
 
417
            // Set the given bytes as the content
 
418
            ByteChunk bc = (ByteChunk) param;
 
419
            int length = bc.getLength();
 
420
            bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length);
 
421
            request.setContentLength(length);
 
422
            first = false;
 
423
            empty = false;
 
424
            replay = true;
 
425
 
 
426
        } else if (actionCode == ActionCode.ASYNC_START) {
 
427
            asyncStateMachine.asyncStart((AsyncContextCallback) param);
 
428
        } else if (actionCode == ActionCode.ASYNC_DISPATCHED) {
 
429
            asyncStateMachine.asyncDispatched();
 
430
        } else if (actionCode == ActionCode.ASYNC_TIMEOUT) {
 
431
            AtomicBoolean result = (AtomicBoolean) param;
 
432
            result.set(asyncStateMachine.asyncTimeout());
 
433
        } else if (actionCode == ActionCode.ASYNC_RUN) {
 
434
            asyncStateMachine.asyncRun((Runnable) param);
 
435
        } else if (actionCode == ActionCode.ASYNC_ERROR) {
 
436
            asyncStateMachine.asyncError();
 
437
        } else if (actionCode == ActionCode.ASYNC_IS_STARTED) {
 
438
            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncStarted());
 
439
        } else if (actionCode == ActionCode.ASYNC_IS_DISPATCHING) {
 
440
            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncDispatching());
 
441
        } else if (actionCode == ActionCode.ASYNC_IS_ASYNC) {
 
442
            ((AtomicBoolean) param).set(asyncStateMachine.isAsync());
 
443
        } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) {
 
444
            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut());
 
445
        }  else {
 
446
            actionInternal(actionCode, param);
 
447
        }
 
448
    }
 
449
 
 
450
    // Methods called by action()
 
451
    protected abstract void actionInternal(ActionCode actionCode, Object param);
 
452
    protected abstract void flush(boolean tbd) throws IOException;
 
453
    protected abstract void finish() throws IOException;
 
454
 
 
455
 
 
456
    @Override
 
457
    public SocketState asyncDispatch(SocketStatus status) {
 
458
 
 
459
        RequestInfo rp = request.getRequestProcessor();
 
460
        try {
 
461
            rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
 
462
            error = !adapter.asyncDispatch(request, response, status);
 
463
        } catch (InterruptedIOException e) {
 
464
            error = true;
 
465
        } catch (Throwable t) {
 
466
            ExceptionUtils.handleThrowable(t);
 
467
            getLog().error(sm.getString("http11processor.request.process"), t);
 
468
            error = true;
 
469
        } finally {
 
470
            if (error) {
 
471
                // 500 - Internal Server Error
 
472
                response.setStatus(500);
 
473
                adapter.log(request, response, 0);
 
474
            }
 
475
        }
 
476
 
 
477
        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
 
478
 
 
479
        if (isAsync()) {
 
480
            if (error) {
 
481
                request.updateCounters();
 
482
                return SocketState.CLOSED;
 
483
            } else {
 
484
                return SocketState.LONG;
 
485
            }
 
486
        } else {
 
487
            request.updateCounters();
 
488
            if (error) {
 
489
                return SocketState.CLOSED;
 
490
            } else {
 
491
                return SocketState.OPEN;
 
492
            }
 
493
        }
 
494
    }
 
495
 
 
496
 
 
497
    @Override
 
498
    protected final boolean isComet() {
 
499
        // AJP does not support Comet
 
500
        return false;
 
501
    }
 
502
 
 
503
    @Override
 
504
    public SocketState event(SocketStatus status) throws IOException {
 
505
        // Should never reach this code but in case we do...
 
506
        throw new IOException(
 
507
                sm.getString("ajpprocessor.comet.notsupported"));
 
508
    }
 
509
 
 
510
    /**
 
511
     * Recycle the processor, ready for the next request which may be on the
 
512
     * same connection or a different connection.
 
513
     * 
 
514
     * @param socketClosing Indicates if the socket is about to be closed
 
515
     *                      allowing the processor to perform any additional
 
516
     *                      clean-up that may be required
 
517
     */
 
518
    public void recycle(boolean socketClosing) {
 
519
        asyncStateMachine.recycle();
 
520
 
 
521
        // Recycle Request object
 
522
        first = true;
 
523
        endOfStream = false;
 
524
        empty = true;
 
525
        replay = false;
 
526
        finished = false;
 
527
        request.recycle();
 
528
        response.recycle();
 
529
        certificates.recycle();
 
530
        byteCount = 0;
 
531
    }
 
532
 
 
533
    // ------------------------------------------------------ Protected Methods
 
534
 
 
535
 
 
536
    /**
 
537
     * After reading the request headers, we have to setup the request filters.
 
538
     */
 
539
    protected void prepareRequest() {
 
540
 
 
541
        // Translate the HTTP method code to a String.
 
542
        byte methodCode = requestHeaderMessage.getByte();
 
543
        if (methodCode != Constants.SC_M_JK_STORED) {
 
544
            String methodName = Constants.getMethodForCode(methodCode - 1);
 
545
            request.method().setString(methodName);
 
546
        }
 
547
 
 
548
        requestHeaderMessage.getBytes(request.protocol());
 
549
        requestHeaderMessage.getBytes(request.requestURI());
 
550
 
 
551
        requestHeaderMessage.getBytes(request.remoteAddr());
 
552
        requestHeaderMessage.getBytes(request.remoteHost());
 
553
        requestHeaderMessage.getBytes(request.localName());
 
554
        request.setLocalPort(requestHeaderMessage.getInt());
 
555
 
 
556
        boolean isSSL = requestHeaderMessage.getByte() != 0;
 
557
        if (isSSL) {
 
558
            request.scheme().setString("https");
 
559
        }
 
560
 
 
561
        // Decode headers
 
562
        MimeHeaders headers = request.getMimeHeaders();
 
563
 
 
564
        int hCount = requestHeaderMessage.getInt();
 
565
        for(int i = 0 ; i < hCount ; i++) {
 
566
            String hName = null;
 
567
 
 
568
            // Header names are encoded as either an integer code starting
 
569
            // with 0xA0, or as a normal string (in which case the first
 
570
            // two bytes are the length).
 
571
            int isc = requestHeaderMessage.peekInt();
 
572
            int hId = isc & 0xFF;
 
573
 
 
574
            MessageBytes vMB = null;
 
575
            isc &= 0xFF00;
 
576
            if(0xA000 == isc) {
 
577
                requestHeaderMessage.getInt(); // To advance the read position
 
578
                hName = Constants.getHeaderForCode(hId - 1);
 
579
                vMB = headers.addValue(hName);
 
580
            } else {
 
581
                // reset hId -- if the header currently being read
 
582
                // happens to be 7 or 8 bytes long, the code below
 
583
                // will think it's the content-type header or the
 
584
                // content-length header - SC_REQ_CONTENT_TYPE=7,
 
585
                // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
 
586
                // behaviour.  see bug 5861 for more information.
 
587
                hId = -1;
 
588
                requestHeaderMessage.getBytes(tmpMB);
 
589
                ByteChunk bc = tmpMB.getByteChunk();
 
590
                vMB = headers.addValue(bc.getBuffer(),
 
591
                        bc.getStart(), bc.getLength());
 
592
            }
 
593
 
 
594
            requestHeaderMessage.getBytes(vMB);
 
595
 
 
596
            if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
 
597
                    (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
 
598
                // just read the content-length header, so set it
 
599
                long cl = vMB.getLong();
 
600
                if(cl < Integer.MAX_VALUE)
 
601
                    request.setContentLength( (int)cl );
 
602
            } else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
 
603
                    (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
 
604
                // just read the content-type header, so set it
 
605
                ByteChunk bchunk = vMB.getByteChunk();
 
606
                request.contentType().setBytes(bchunk.getBytes(),
 
607
                        bchunk.getOffset(),
 
608
                        bchunk.getLength());
 
609
            }
 
610
        }
 
611
 
 
612
        // Decode extra attributes
 
613
        boolean secret = false;
 
614
        byte attributeCode;
 
615
        while ((attributeCode = requestHeaderMessage.getByte())
 
616
                != Constants.SC_A_ARE_DONE) {
 
617
 
 
618
            switch (attributeCode) {
 
619
 
 
620
            case Constants.SC_A_REQ_ATTRIBUTE :
 
621
                requestHeaderMessage.getBytes(tmpMB);
 
622
                String n = tmpMB.toString();
 
623
                requestHeaderMessage.getBytes(tmpMB);
 
624
                String v = tmpMB.toString();
 
625
                /*
 
626
                 * AJP13 misses to forward the remotePort.
 
627
                 * Allow the AJP connector to add this info via
 
628
                 * a private request attribute.
 
629
                 * We will accept the forwarded data as the remote port,
 
630
                 * and remove it from the public list of request attributes.
 
631
                 */
 
632
                if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) {
 
633
                    try {
 
634
                        request.setRemotePort(Integer.parseInt(v));
 
635
                    } catch (NumberFormatException nfe) {
 
636
                        // Ignore invalid value
 
637
                    }
 
638
                } else {
 
639
                    request.setAttribute(n, v );
 
640
                }
 
641
                break;
 
642
 
 
643
            case Constants.SC_A_CONTEXT :
 
644
                requestHeaderMessage.getBytes(tmpMB);
 
645
                // nothing
 
646
                break;
 
647
 
 
648
            case Constants.SC_A_SERVLET_PATH :
 
649
                requestHeaderMessage.getBytes(tmpMB);
 
650
                // nothing
 
651
                break;
 
652
 
 
653
            case Constants.SC_A_REMOTE_USER :
 
654
                if (tomcatAuthentication) {
 
655
                    // ignore server
 
656
                    requestHeaderMessage.getBytes(tmpMB);
 
657
                } else {
 
658
                    requestHeaderMessage.getBytes(request.getRemoteUser());
 
659
                }
 
660
                break;
 
661
 
 
662
            case Constants.SC_A_AUTH_TYPE :
 
663
                if (tomcatAuthentication) {
 
664
                    // ignore server
 
665
                    requestHeaderMessage.getBytes(tmpMB);
 
666
                } else {
 
667
                    requestHeaderMessage.getBytes(request.getAuthType());
 
668
                }
 
669
                break;
 
670
 
 
671
            case Constants.SC_A_QUERY_STRING :
 
672
                requestHeaderMessage.getBytes(request.queryString());
 
673
                break;
 
674
 
 
675
            case Constants.SC_A_JVM_ROUTE :
 
676
                requestHeaderMessage.getBytes(request.instanceId());
 
677
                break;
 
678
 
 
679
            case Constants.SC_A_SSL_CERT :
 
680
                request.scheme().setString("https");
 
681
                // SSL certificate extraction is lazy, moved to JkCoyoteHandler
 
682
                requestHeaderMessage.getBytes(certificates);
 
683
                break;
 
684
 
 
685
            case Constants.SC_A_SSL_CIPHER :
 
686
                request.scheme().setString("https");
 
687
                requestHeaderMessage.getBytes(tmpMB);
 
688
                request.setAttribute(SSLSupport.CIPHER_SUITE_KEY,
 
689
                        tmpMB.toString());
 
690
                break;
 
691
 
 
692
            case Constants.SC_A_SSL_SESSION :
 
693
                request.scheme().setString("https");
 
694
                requestHeaderMessage.getBytes(tmpMB);
 
695
                request.setAttribute(SSLSupport.SESSION_ID_KEY,
 
696
                        tmpMB.toString());
 
697
                break;
 
698
 
 
699
            case Constants.SC_A_SSL_KEY_SIZE :
 
700
                request.setAttribute(SSLSupport.KEY_SIZE_KEY,
 
701
                        Integer.valueOf(requestHeaderMessage.getInt()));
 
702
                break;
 
703
 
 
704
            case Constants.SC_A_STORED_METHOD:
 
705
                requestHeaderMessage.getBytes(request.method());
 
706
                break;
 
707
 
 
708
            case Constants.SC_A_SECRET:
 
709
                requestHeaderMessage.getBytes(tmpMB);
 
710
                if (requiredSecret != null) {
 
711
                    secret = true;
 
712
                    if (!tmpMB.equals(requiredSecret)) {
 
713
                        response.setStatus(403);
 
714
                        adapter.log(request, response, 0);
 
715
                        error = true;
 
716
                    }
 
717
                }
 
718
                break;
 
719
 
 
720
            default:
 
721
                // Ignore unknown attribute for backward compatibility
 
722
                break;
 
723
 
 
724
            }
 
725
 
 
726
        }
 
727
 
 
728
        // Check if secret was submitted if required
 
729
        if ((requiredSecret != null) && !secret) {
 
730
            response.setStatus(403);
 
731
            adapter.log(request, response, 0);
 
732
            error = true;
 
733
        }
 
734
 
 
735
        // Check for a full URI (including protocol://host:port/)
 
736
        ByteChunk uriBC = request.requestURI().getByteChunk();
 
737
        if (uriBC.startsWithIgnoreCase("http", 0)) {
 
738
 
 
739
            int pos = uriBC.indexOf("://", 0, 3, 4);
 
740
            int uriBCStart = uriBC.getStart();
 
741
            int slashPos = -1;
 
742
            if (pos != -1) {
 
743
                byte[] uriB = uriBC.getBytes();
 
744
                slashPos = uriBC.indexOf('/', pos + 3);
 
745
                if (slashPos == -1) {
 
746
                    slashPos = uriBC.getLength();
 
747
                    // Set URI as "/"
 
748
                    request.requestURI().setBytes
 
749
                    (uriB, uriBCStart + pos + 1, 1);
 
750
                } else {
 
751
                    request.requestURI().setBytes
 
752
                    (uriB, uriBCStart + slashPos,
 
753
                            uriBC.getLength() - slashPos);
 
754
                }
 
755
                MessageBytes hostMB = headers.setValue("host");
 
756
                hostMB.setBytes(uriB, uriBCStart + pos + 3,
 
757
                        slashPos - pos - 3);
 
758
            }
 
759
 
 
760
        }
 
761
 
 
762
        MessageBytes valueMB = request.getMimeHeaders().getValue("host");
 
763
        parseHost(valueMB);
 
764
 
 
765
    }
 
766
 
 
767
 
 
768
    /**
 
769
     * Parse host.
 
770
     */
 
771
    protected void parseHost(MessageBytes valueMB) {
 
772
 
 
773
        if (valueMB == null || valueMB.isNull()) {
 
774
            // HTTP/1.0
 
775
            request.setServerPort(request.getLocalPort());
 
776
            try {
 
777
                request.serverName().duplicate(request.localName());
 
778
            } catch (IOException e) {
 
779
                response.setStatus(400);
 
780
                adapter.log(request, response, 0);
 
781
                error = true;
 
782
            }
 
783
            return;
 
784
        }
 
785
 
 
786
        ByteChunk valueBC = valueMB.getByteChunk();
 
787
        byte[] valueB = valueBC.getBytes();
 
788
        int valueL = valueBC.getLength();
 
789
        int valueS = valueBC.getStart();
 
790
        int colonPos = -1;
 
791
        if (hostNameC.length < valueL) {
 
792
            hostNameC = new char[valueL];
 
793
        }
 
794
 
 
795
        boolean ipv6 = (valueB[valueS] == '[');
 
796
        boolean bracketClosed = false;
 
797
        for (int i = 0; i < valueL; i++) {
 
798
            char b = (char) valueB[i + valueS];
 
799
            hostNameC[i] = b;
 
800
            if (b == ']') {
 
801
                bracketClosed = true;
 
802
            } else if (b == ':') {
 
803
                if (!ipv6 || bracketClosed) {
 
804
                    colonPos = i;
 
805
                    break;
 
806
                }
 
807
            }
 
808
        }
 
809
 
 
810
        if (colonPos < 0) {
 
811
            if (request.scheme().equalsIgnoreCase("https")) {
 
812
                // 443 - Default HTTPS port
 
813
                request.setServerPort(443);
 
814
            } else {
 
815
                // 80 - Default HTTTP port
 
816
                request.setServerPort(80);
 
817
            }
 
818
            request.serverName().setChars(hostNameC, 0, valueL);
 
819
        } else {
 
820
 
 
821
            request.serverName().setChars(hostNameC, 0, colonPos);
 
822
 
 
823
            int port = 0;
 
824
            int mult = 1;
 
825
            for (int i = valueL - 1; i > colonPos; i--) {
 
826
                int charValue = HexUtils.getDec(valueB[i + valueS]);
 
827
                if (charValue == -1) {
 
828
                    // Invalid character
 
829
                    error = true;
 
830
                    // 400 - Bad request
 
831
                    response.setStatus(400);
 
832
                    adapter.log(request, response, 0);
 
833
                    break;
 
834
                }
 
835
                port = port + (charValue * mult);
 
836
                mult = 10 * mult;
 
837
            }
 
838
            request.setServerPort(port);
 
839
        }
 
840
    }
 
841
 
 
842
 
 
843
    /**
 
844
     * When committing the response, we have to validate the set of headers, as
 
845
     * well as setup the response filters.
 
846
     */
 
847
    protected void prepareResponse()
 
848
    throws IOException {
 
849
 
 
850
        response.setCommitted(true);
 
851
 
 
852
        responseHeaderMessage.reset();
 
853
        responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
 
854
 
 
855
        // HTTP header contents
 
856
        responseHeaderMessage.appendInt(response.getStatus());
 
857
        String message = null;
 
858
        if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER &&
 
859
                HttpMessages.isSafeInHttpHeader(response.getMessage())) {
 
860
            message = response.getMessage();
 
861
        }
 
862
        if (message == null){
 
863
            message = HttpMessages.getMessage(response.getStatus());
 
864
        }
 
865
        if (message == null) {
 
866
            // mod_jk + httpd 2.x fails with a null status message - bug 45026
 
867
            message = Integer.toString(response.getStatus());
 
868
        }
 
869
        tmpMB.setString(message);
 
870
        responseHeaderMessage.appendBytes(tmpMB);
 
871
 
 
872
        // Special headers
 
873
        MimeHeaders headers = response.getMimeHeaders();
 
874
        String contentType = response.getContentType();
 
875
        if (contentType != null) {
 
876
            headers.setValue("Content-Type").setString(contentType);
 
877
        }
 
878
        String contentLanguage = response.getContentLanguage();
 
879
        if (contentLanguage != null) {
 
880
            headers.setValue("Content-Language").setString(contentLanguage);
 
881
        }
 
882
        long contentLength = response.getContentLengthLong();
 
883
        if (contentLength >= 0) {
 
884
            headers.setValue("Content-Length").setLong(contentLength);
 
885
        }
 
886
 
 
887
        // Other headers
 
888
        int numHeaders = headers.size();
 
889
        responseHeaderMessage.appendInt(numHeaders);
 
890
        for (int i = 0; i < numHeaders; i++) {
 
891
            MessageBytes hN = headers.getName(i);
 
892
            int hC = Constants.getResponseAjpIndex(hN.toString());
 
893
            if (hC > 0) {
 
894
                responseHeaderMessage.appendInt(hC);
 
895
            }
 
896
            else {
 
897
                responseHeaderMessage.appendBytes(hN);
 
898
            }
 
899
            MessageBytes hV=headers.getValue(i);
 
900
            responseHeaderMessage.appendBytes(hV);
 
901
        }
 
902
 
 
903
        // Write to buffer
 
904
        responseHeaderMessage.end();
 
905
        output(responseHeaderMessage.getBuffer(), 0,
 
906
                responseHeaderMessage.getLen());
 
907
    }
 
908
 
 
909
    // Methods called by prepareResponse()
 
910
    protected abstract void output(byte[] src, int offset, int length)
 
911
    throws IOException;
 
912
 
 
913
 
 
914
    // ------------------------------------- InputStreamInputBuffer Inner Class
 
915
 
 
916
 
 
917
    /**
 
918
     * This class is an input buffer which will read its data from an input
 
919
     * stream.
 
920
     */
 
921
    protected class SocketInputBuffer
 
922
    implements InputBuffer {
 
923
 
 
924
 
 
925
        /**
 
926
         * Read bytes into the specified chunk.
 
927
         */
 
928
        @Override
 
929
        public int doRead(ByteChunk chunk, Request req )
 
930
        throws IOException {
 
931
 
 
932
            if (endOfStream) {
 
933
                return -1;
 
934
            }
 
935
            if (first && req.getContentLengthLong() > 0) {
 
936
                // Handle special first-body-chunk
 
937
                if (!receive()) {
 
938
                    return 0;
 
939
                }
 
940
            } else if (empty) {
 
941
                if (!refillReadBuffer()) {
 
942
                    return -1;
 
943
                }
 
944
            }
 
945
            ByteChunk bc = bodyBytes.getByteChunk();
 
946
            chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength());
 
947
            empty = true;
 
948
            return chunk.getLength();
 
949
 
 
950
        }
 
951
 
 
952
    }
 
953
 
 
954
    // Methods used by SocketInputBuffer
 
955
    protected abstract boolean receive() throws IOException;
 
956
    protected abstract boolean refillReadBuffer() throws IOException;
848
957
}