~ubuntu-branches/ubuntu/natty/tomcat6/natty-proposed

« back to all changes in this revision

Viewing changes to .pc/0017-CVE-2011-3190.patch/java/org/apache/coyote/ajp/AjpProcessor.java

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-09-26 11:27:14 UTC
  • Revision ID: package-import@ubuntu.com-20110926112714-ngfuvuxfnr5oe2x8
Tags: 6.0.28-10ubuntu2.2
* SECURITY UPDATE: information disclosure via log file
  - debian/patches/0015-CVE-2011-2204.patch: fix logging in
    java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java,
    java/org/apache/catalina/users/MemoryUserDatabase.java,
    java/org/apache/catalina/users/MemoryUser.java.
  - CVE-2011-2204
* SECURITY UPDATE: file restriction bypass or denial of service via
  untrusted web application.
  - debian/patches/0016-CVE-2011-2526.patch: check canonical name in
    java/org/apache/catalina/connector/LocalStrings.properties,
    java/org/apache/catalina/connector/Request.java,
    java/org/apache/catalina/servlets/DefaultServlet.java,
    java/org/apache/coyote/http11/Http11AprProcessor.java,
    java/org/apache/coyote/http11/LocalStrings.properties,
    java/org/apache/tomcat/util/net/AprEndpoint.java,
    java/org/apache/tomcat/util/net/NioEndpoint.java.
  - CVE-2011-2526
* SECURITY UPDATE: AJP request spoofing and authentication bypass
  (LP: #843701)
  - debian/patches/0017-CVE-2011-3190.patch: Properly handle request
    bodies in java/org/apache/coyote/ajp/AjpAprProcessor.java,
    java/org/apache/coyote/ajp/AjpProcessor.java.
  - CVE-2011-3190
* SECURITY UPDATE: HTTP DIGEST authentication weaknesses
  - debian/patches/0018-CVE-2011-1184.patch: add new nonce options in
    java/org/apache/catalina/authenticator/DigestAuthenticator.java,
    java/org/apache/catalina/authenticator/LocalStrings.properties,
    java/org/apache/catalina/authenticator/mbeans-descriptors.xml,
    java/org/apache/catalina/realm/RealmBase.java,
    webapps/docs/config/valve.xml.
  - CVE-2011-1184

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 *  contributor license agreements.  See the NOTICE file distributed with
 
4
 *  this work for additional information regarding copyright ownership.
 
5
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 
6
 *  (the "License"); you may not use this file except in compliance with
 
7
 *  the License.  You may obtain a copy of the License at
 
8
 *
 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 *  Unless required by applicable law or agreed to in writing, software
 
12
 *  distributed under the License is distributed on an "AS IS" BASIS,
 
13
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 *  See the License for the specific language governing permissions and
 
15
 *  limitations under the License.
 
16
 */
 
17
 
 
18
package org.apache.coyote.ajp;
 
19
 
 
20
import java.io.ByteArrayInputStream;
 
21
import java.io.IOException;
 
22
import java.io.InputStream;
 
23
import java.io.InterruptedIOException;
 
24
import java.io.OutputStream;
 
25
import java.net.InetAddress;
 
26
import java.net.Socket;
 
27
import java.security.cert.CertificateFactory;
 
28
import java.security.cert.X509Certificate;
 
29
 
 
30
import org.apache.coyote.ActionCode;
 
31
import org.apache.coyote.ActionHook;
 
32
import org.apache.coyote.Adapter;
 
33
import org.apache.coyote.InputBuffer;
 
34
import org.apache.coyote.OutputBuffer;
 
35
import org.apache.coyote.Request;
 
36
import org.apache.coyote.RequestInfo;
 
37
import org.apache.coyote.Response;
 
38
import org.apache.tomcat.util.buf.ByteChunk;
 
39
import org.apache.tomcat.util.buf.HexUtils;
 
40
import org.apache.tomcat.util.buf.MessageBytes;
 
41
import org.apache.tomcat.util.http.HttpMessages;
 
42
import org.apache.tomcat.util.http.MimeHeaders;
 
43
import org.apache.tomcat.util.net.JIoEndpoint;
 
44
import org.apache.tomcat.util.res.StringManager;
 
45
 
 
46
 
 
47
/**
 
48
 * Processes HTTP requests.
 
49
 *
 
50
 * @author Remy Maucherat
 
51
 * @author Henri Gomez
 
52
 * @author Dan Milstein
 
53
 * @author Keith Wannamaker
 
54
 * @author Kevin Seguin
 
55
 * @author Costin Manolache
 
56
 * @author Bill Barker
 
57
 */
 
58
public class AjpProcessor implements ActionHook {
 
59
 
 
60
 
 
61
    /**
 
62
     * Logger.
 
63
     */
 
64
    protected static org.apache.juli.logging.Log log
 
65
        = org.apache.juli.logging.LogFactory.getLog(AjpProcessor.class);
 
66
 
 
67
    /**
 
68
     * The string manager for this package.
 
69
     */
 
70
    protected static StringManager sm =
 
71
        StringManager.getManager(Constants.Package);
 
72
 
 
73
 
 
74
    // ----------------------------------------------------------- Constructors
 
75
 
 
76
 
 
77
    public AjpProcessor(int packetSize, JIoEndpoint endpoint) {
 
78
 
 
79
        this.endpoint = endpoint;
 
80
 
 
81
        request = new Request();
 
82
        request.setInputBuffer(new SocketInputBuffer());
 
83
 
 
84
        response = new Response();
 
85
        response.setHook(this);
 
86
        response.setOutputBuffer(new SocketOutputBuffer());
 
87
        request.setResponse(response);
 
88
 
 
89
        this.packetSize = packetSize;
 
90
        requestHeaderMessage = new AjpMessage(packetSize);
 
91
        responseHeaderMessage = new AjpMessage(packetSize);
 
92
        bodyMessage = new AjpMessage(packetSize);
 
93
 
 
94
        // Set the get body message buffer
 
95
        AjpMessage getBodyMessage = new AjpMessage(16);
 
96
        getBodyMessage.reset();
 
97
        getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK);
 
98
        // Adjust allowed size if packetSize != default (Constants.MAX_PACKET_SIZE)
 
99
        getBodyMessage.appendInt(Constants.MAX_READ_SIZE + packetSize - Constants.MAX_PACKET_SIZE);
 
100
        getBodyMessage.end();
 
101
        getBodyMessageArray = new byte[getBodyMessage.getLen()];
 
102
        System.arraycopy(getBodyMessage.getBuffer(), 0, getBodyMessageArray, 
 
103
                         0, getBodyMessage.getLen());
 
104
 
 
105
        // Cause loading of HexUtils
 
106
        int foo = HexUtils.DEC[0];
 
107
 
 
108
        // Cause loading of HttpMessages
 
109
        HttpMessages.getMessage(200);
 
110
 
 
111
    }
 
112
 
 
113
 
 
114
    // ----------------------------------------------------- Instance Variables
 
115
 
 
116
 
 
117
    /**
 
118
     * Associated adapter.
 
119
     */
 
120
    protected Adapter adapter = null;
 
121
 
 
122
 
 
123
    /**
 
124
     * Request object.
 
125
     */
 
126
    protected Request request = null;
 
127
 
 
128
 
 
129
    /**
 
130
     * Response object.
 
131
     */
 
132
    protected Response response = null;
 
133
 
 
134
 
 
135
    /**
 
136
     * The socket timeout used when reading the first block of the request
 
137
     * header.
 
138
     */
 
139
    protected int packetSize;
 
140
 
 
141
    /**
 
142
     * Header message. Note that this header is merely the one used during the
 
143
     * processing of the first message of a "request", so it might not be a request
 
144
     * header. It will stay unchanged during the processing of the whole request.
 
145
     */
 
146
    protected AjpMessage requestHeaderMessage = null;
 
147
 
 
148
 
 
149
    /**
 
150
     * Message used for response header composition.
 
151
     */
 
152
    protected AjpMessage responseHeaderMessage = null;
 
153
 
 
154
 
 
155
    /**
 
156
     * Body message.
 
157
     */
 
158
    protected AjpMessage bodyMessage = null;
 
159
 
 
160
 
 
161
    /**
 
162
     * Body message.
 
163
     */
 
164
    protected MessageBytes bodyBytes = MessageBytes.newInstance();
 
165
 
 
166
 
 
167
    /**
 
168
     * State flag.
 
169
     */
 
170
    protected boolean started = false;
 
171
 
 
172
 
 
173
    /**
 
174
     * Error flag.
 
175
     */
 
176
    protected boolean error = false;
 
177
 
 
178
 
 
179
    /**
 
180
     * Socket associated with the current connection.
 
181
     */
 
182
    protected Socket socket;
 
183
 
 
184
    
 
185
    /**
 
186
     * Input stream.
 
187
     */
 
188
    protected InputStream input;
 
189
    
 
190
    
 
191
    /**
 
192
     * Output stream.
 
193
     */
 
194
    protected OutputStream output;
 
195
    
 
196
 
 
197
    /**
 
198
     * Host name (used to avoid useless B2C conversion on the host name).
 
199
     */
 
200
    protected char[] hostNameC = new char[0];
 
201
 
 
202
 
 
203
    /**
 
204
     * Associated endpoint.
 
205
     */
 
206
    protected JIoEndpoint endpoint;
 
207
 
 
208
 
 
209
    /**
 
210
     * The socket timeout used when reading the first block of the request
 
211
     * header.
 
212
     */
 
213
    protected long readTimeout;
 
214
 
 
215
 
 
216
    /**
 
217
     * Temp message bytes used for processing.
 
218
     */
 
219
    protected MessageBytes tmpMB = MessageBytes.newInstance();
 
220
 
 
221
 
 
222
    /**
 
223
     * Byte chunk for certs.
 
224
     */
 
225
    protected MessageBytes certificates = MessageBytes.newInstance();
 
226
 
 
227
 
 
228
    /**
 
229
     * End of stream flag.
 
230
     */
 
231
    protected boolean endOfStream = false;
 
232
 
 
233
 
 
234
    /**
 
235
     * Body empty flag.
 
236
     */
 
237
    protected boolean empty = true;
 
238
 
 
239
 
 
240
    /**
 
241
     * First read.
 
242
     */
 
243
    protected boolean first = true;
 
244
 
 
245
 
 
246
    /**
 
247
     * Replay read.
 
248
     */
 
249
    protected boolean replay = false;
 
250
 
 
251
 
 
252
    /**
 
253
     * Finished response.
 
254
     */
 
255
    protected boolean finished = false;
 
256
 
 
257
 
 
258
    /**
 
259
     * Direct buffer used for sending right away a get body message.
 
260
     */
 
261
    protected final byte[] getBodyMessageArray;
 
262
 
 
263
 
 
264
    /**
 
265
     * Direct buffer used for sending right away a pong message.
 
266
     */
 
267
    protected static final byte[] pongMessageArray;
 
268
 
 
269
 
 
270
    /**
 
271
     * End message array.
 
272
     */
 
273
    protected static final byte[] endMessageArray;
 
274
 
 
275
    /**
 
276
     * Flush message array.
 
277
     */
 
278
    protected static final byte[] flushMessageArray;
 
279
 
 
280
 
 
281
    // ----------------------------------------------------- Static Initializer
 
282
 
 
283
 
 
284
    static {
 
285
 
 
286
        // Set the read body message buffer
 
287
        AjpMessage pongMessage = new AjpMessage(16);
 
288
        pongMessage.reset();
 
289
        pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY);
 
290
        pongMessage.end();
 
291
        pongMessageArray = new byte[pongMessage.getLen()];
 
292
        System.arraycopy(pongMessage.getBuffer(), 0, pongMessageArray, 
 
293
                0, pongMessage.getLen());
 
294
 
 
295
        // Allocate the end message array
 
296
        AjpMessage endMessage = new AjpMessage(16);
 
297
        endMessage.reset();
 
298
        endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE);
 
299
        endMessage.appendByte(1);
 
300
        endMessage.end();
 
301
        endMessageArray = new byte[endMessage.getLen()];
 
302
        System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0,
 
303
                endMessage.getLen());
 
304
 
 
305
        // Allocate the flush message array
 
306
        AjpMessage flushMessage = new AjpMessage(16);
 
307
        flushMessage.reset();
 
308
        flushMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
 
309
        flushMessage.appendInt(0);
 
310
        flushMessage.appendByte(0);
 
311
        flushMessage.end();
 
312
        flushMessageArray = new byte[flushMessage.getLen()];
 
313
        System.arraycopy(flushMessage.getBuffer(), 0, flushMessageArray, 0,
 
314
                flushMessage.getLen());
 
315
 
 
316
    }
 
317
 
 
318
 
 
319
    // ------------------------------------------------------------- Properties
 
320
 
 
321
 
 
322
    /**
 
323
     * Use Tomcat authentication ?
 
324
     */
 
325
    protected boolean tomcatAuthentication = true;
 
326
    public boolean getTomcatAuthentication() { return tomcatAuthentication; }
 
327
    public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; }
 
328
 
 
329
 
 
330
    /**
 
331
     * Required secret.
 
332
     */
 
333
    protected String requiredSecret = null;
 
334
    public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; }
 
335
 
 
336
 
 
337
    /**
 
338
     * The number of milliseconds Tomcat will wait for a subsequent request
 
339
     * before closing the connection. The default is the same as for
 
340
     * Apache HTTP Server (15 000 milliseconds).
 
341
     */
 
342
    protected int keepAliveTimeout = -1;
 
343
    public int getKeepAliveTimeout() { return keepAliveTimeout; }
 
344
    public void setKeepAliveTimeout(int timeout) { keepAliveTimeout = timeout; }
 
345
 
 
346
 
 
347
    // --------------------------------------------------------- Public Methods
 
348
 
 
349
 
 
350
    /** Get the request associated with this processor.
 
351
     *
 
352
     * @return The request
 
353
     */
 
354
    public Request getRequest() {
 
355
        return request;
 
356
    }
 
357
 
 
358
 
 
359
    /**
 
360
     * Process pipelined HTTP requests using the specified input and output
 
361
     * streams.
 
362
     *
 
363
     * @throws IOException error during an I/O operation
 
364
     */
 
365
    public void process(Socket socket)
 
366
        throws IOException {
 
367
        RequestInfo rp = request.getRequestProcessor();
 
368
        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
 
369
 
 
370
        // Setting up the socket
 
371
        this.socket = socket;
 
372
        input = socket.getInputStream();
 
373
        output = socket.getOutputStream();
 
374
        int soTimeout = -1;
 
375
        if (keepAliveTimeout > 0) {
 
376
            soTimeout = socket.getSoTimeout();
 
377
        }
 
378
 
 
379
        // Error flag
 
380
        error = false;
 
381
 
 
382
        while (started && !error) {
 
383
 
 
384
            // Parsing the request header
 
385
            try {
 
386
                // Set keep alive timeout if enabled
 
387
                if (keepAliveTimeout > 0) {
 
388
                    socket.setSoTimeout(keepAliveTimeout);
 
389
                }
 
390
                // Get first message of the request
 
391
                if (!readMessage(requestHeaderMessage)) {
 
392
                    // This means a connection timeout
 
393
                    rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
 
394
                    break;
 
395
                }
 
396
                // Set back timeout if keep alive timeout is enabled
 
397
                if (keepAliveTimeout > 0) {
 
398
                    socket.setSoTimeout(soTimeout);
 
399
                }
 
400
                // Check message type, process right away and break if
 
401
                // not regular request processing
 
402
                int type = requestHeaderMessage.getByte();
 
403
                if (type == Constants.JK_AJP13_CPING_REQUEST) {
 
404
                    try {
 
405
                        output.write(pongMessageArray);
 
406
                    } catch (IOException e) {
 
407
                        error = true;
 
408
                    }
 
409
                    continue;
 
410
                } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) {
 
411
                    // Usually the servlet didn't read the previous request body
 
412
                    if(log.isDebugEnabled()) {
 
413
                        log.debug("Unexpected message: "+type);
 
414
                    }
 
415
                    continue;
 
416
                }
 
417
 
 
418
                request.setStartTime(System.currentTimeMillis());
 
419
            } catch (IOException e) {
 
420
                error = true;
 
421
                break;
 
422
            } catch (Throwable t) {
 
423
                log.debug(sm.getString("ajpprocessor.header.error"), t);
 
424
                // 400 - Bad Request
 
425
                response.setStatus(400);
 
426
                error = true;
 
427
            }
 
428
 
 
429
            // Setting up filters, and parse some request headers
 
430
            rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
 
431
            try {
 
432
                prepareRequest();
 
433
            } catch (Throwable t) {
 
434
                log.debug(sm.getString("ajpprocessor.request.prepare"), t);
 
435
                // 400 - Internal Server Error
 
436
                response.setStatus(400);
 
437
                error = true;
 
438
            }
 
439
 
 
440
            // Process the request in the adapter
 
441
            if (!error) {
 
442
                try {
 
443
                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
 
444
                    adapter.service(request, response);
 
445
                } catch (InterruptedIOException e) {
 
446
                    error = true;
 
447
                } catch (Throwable t) {
 
448
                    log.error(sm.getString("ajpprocessor.request.process"), t);
 
449
                    // 500 - Internal Server Error
 
450
                    response.setStatus(500);
 
451
                    error = true;
 
452
                }
 
453
            }
 
454
 
 
455
            // Finish the response if not done yet
 
456
            if (!finished) {
 
457
                try {
 
458
                    finish();
 
459
                } catch (Throwable t) {
 
460
                    error = true;
 
461
                }
 
462
            }
 
463
 
 
464
            // If there was an error, make sure the request is counted as
 
465
            // and error, and update the statistics counter
 
466
            if (error) {
 
467
                response.setStatus(500);
 
468
            }
 
469
            request.updateCounters();
 
470
 
 
471
            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
 
472
            recycle();
 
473
 
 
474
        }
 
475
 
 
476
        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
 
477
        recycle();
 
478
        input = null;
 
479
        output = null;
 
480
        
 
481
    }
 
482
 
 
483
 
 
484
    // ----------------------------------------------------- ActionHook Methods
 
485
 
 
486
 
 
487
    /**
 
488
     * Send an action to the connector.
 
489
     *
 
490
     * @param actionCode Type of the action
 
491
     * @param param Action parameter
 
492
     */
 
493
    public void action(ActionCode actionCode, Object param) {
 
494
 
 
495
        if (actionCode == ActionCode.ACTION_COMMIT) {
 
496
 
 
497
            if (response.isCommitted())
 
498
                return;
 
499
 
 
500
            // Validate and write response headers
 
501
            try {
 
502
                prepareResponse();
 
503
            } catch (IOException e) {
 
504
                // Set error flag
 
505
                error = true;
 
506
            }
 
507
 
 
508
        } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
 
509
 
 
510
            if (!response.isCommitted()) {
 
511
                // Validate and write response headers
 
512
                try {
 
513
                    prepareResponse();
 
514
                } catch (IOException e) {
 
515
                    // Set error flag
 
516
                    error = true;
 
517
                    return;
 
518
                }
 
519
            }
 
520
 
 
521
            try {
 
522
                flush();
 
523
            } catch (IOException e) {
 
524
                // Set error flag
 
525
                error = true;
 
526
            }
 
527
 
 
528
        } else if (actionCode == ActionCode.ACTION_CLOSE) {
 
529
            // Close
 
530
 
 
531
            // End the processing of the current request, and stop any further
 
532
            // transactions with the client
 
533
 
 
534
            try {
 
535
                finish();
 
536
            } catch (IOException e) {
 
537
                // Set error flag
 
538
                error = true;
 
539
            }
 
540
 
 
541
        } else if (actionCode == ActionCode.ACTION_START) {
 
542
 
 
543
            started = true;
 
544
 
 
545
        } else if (actionCode == ActionCode.ACTION_STOP) {
 
546
 
 
547
            started = false;
 
548
 
 
549
        } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
 
550
 
 
551
            if (!certificates.isNull()) {
 
552
                ByteChunk certData = certificates.getByteChunk();
 
553
                X509Certificate jsseCerts[] = null;
 
554
                ByteArrayInputStream bais =
 
555
                    new ByteArrayInputStream(certData.getBytes(),
 
556
                            certData.getStart(),
 
557
                            certData.getLength());
 
558
                // Fill the elements.
 
559
                try {
 
560
                    CertificateFactory cf =
 
561
                        CertificateFactory.getInstance("X.509");
 
562
                    while(bais.available() > 0) {
 
563
                        X509Certificate cert = (X509Certificate)
 
564
                            cf.generateCertificate(bais);
 
565
                        if(jsseCerts == null) {
 
566
                            jsseCerts = new X509Certificate[1];
 
567
                            jsseCerts[0] = cert;
 
568
                        } else {
 
569
                            X509Certificate [] temp = new X509Certificate[jsseCerts.length+1];
 
570
                            System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length);
 
571
                            temp[jsseCerts.length] = cert;
 
572
                            jsseCerts = temp;
 
573
                        }
 
574
                    }
 
575
                } catch (java.security.cert.CertificateException e) {
 
576
                    log.error(sm.getString("ajpprocessor.certs.fail"), e);
 
577
                    return;
 
578
                }
 
579
                request.setAttribute(JIoEndpoint.CERTIFICATE_KEY, jsseCerts);
 
580
            }
 
581
 
 
582
        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
 
583
 
 
584
            // Get remote host name using a DNS resolution
 
585
            if (request.remoteHost().isNull()) {
 
586
                try {
 
587
                    request.remoteHost().setString(InetAddress.getByName
 
588
                            (request.remoteAddr().toString()).getHostName());
 
589
                } catch (IOException iex) {
 
590
                    // Ignore
 
591
                }
 
592
            }
 
593
 
 
594
        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
 
595
 
 
596
            // Copy from local name for now, which should simply be an address
 
597
            request.localAddr().setString(request.localName().toString());
 
598
 
 
599
        } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
 
600
 
 
601
            // Set the given bytes as the content
 
602
            ByteChunk bc = (ByteChunk) param;
 
603
            int length = bc.getLength();
 
604
            bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length);
 
605
            request.setContentLength(length);
 
606
            first = false;
 
607
            empty = false;
 
608
            replay = true;
 
609
 
 
610
        }
 
611
 
 
612
 
 
613
    }
 
614
 
 
615
 
 
616
    // ------------------------------------------------------ Connector Methods
 
617
 
 
618
 
 
619
    /**
 
620
     * Set the associated adapter.
 
621
     *
 
622
     * @param adapter the new adapter
 
623
     */
 
624
    public void setAdapter(Adapter adapter) {
 
625
        this.adapter = adapter;
 
626
    }
 
627
 
 
628
 
 
629
    /**
 
630
     * Get the associated adapter.
 
631
     *
 
632
     * @return the associated adapter
 
633
     */
 
634
    public Adapter getAdapter() {
 
635
        return adapter;
 
636
    }
 
637
 
 
638
 
 
639
    // ------------------------------------------------------ Protected Methods
 
640
 
 
641
 
 
642
    /**
 
643
     * After reading the request headers, we have to setup the request filters.
 
644
     */
 
645
    protected void prepareRequest() {
 
646
 
 
647
        // Translate the HTTP method code to a String.
 
648
        byte methodCode = requestHeaderMessage.getByte();
 
649
        if (methodCode != Constants.SC_M_JK_STORED) {
 
650
            String methodName = Constants.methodTransArray[(int)methodCode - 1];
 
651
            request.method().setString(methodName);
 
652
        }
 
653
 
 
654
        requestHeaderMessage.getBytes(request.protocol());
 
655
        requestHeaderMessage.getBytes(request.requestURI());
 
656
 
 
657
        requestHeaderMessage.getBytes(request.remoteAddr());
 
658
        requestHeaderMessage.getBytes(request.remoteHost());
 
659
        requestHeaderMessage.getBytes(request.localName());
 
660
        request.setLocalPort(requestHeaderMessage.getInt());
 
661
 
 
662
        boolean isSSL = requestHeaderMessage.getByte() != 0;
 
663
        if (isSSL) {
 
664
            request.scheme().setString("https");
 
665
        }
 
666
 
 
667
        // Decode headers
 
668
        MimeHeaders headers = request.getMimeHeaders();
 
669
 
 
670
        int hCount = requestHeaderMessage.getInt();
 
671
        for(int i = 0 ; i < hCount ; i++) {
 
672
            String hName = null;
 
673
 
 
674
            // Header names are encoded as either an integer code starting
 
675
            // with 0xA0, or as a normal string (in which case the first
 
676
            // two bytes are the length).
 
677
            int isc = requestHeaderMessage.peekInt();
 
678
            int hId = isc & 0xFF;
 
679
 
 
680
            MessageBytes vMB = null;
 
681
            isc &= 0xFF00;
 
682
            if(0xA000 == isc) {
 
683
                requestHeaderMessage.getInt(); // To advance the read position
 
684
                hName = Constants.headerTransArray[hId - 1];
 
685
                vMB = headers.addValue(hName);
 
686
            } else {
 
687
                // reset hId -- if the header currently being read
 
688
                // happens to be 7 or 8 bytes long, the code below
 
689
                // will think it's the content-type header or the
 
690
                // content-length header - SC_REQ_CONTENT_TYPE=7,
 
691
                // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
 
692
                // behaviour.  see bug 5861 for more information.
 
693
                hId = -1;
 
694
                requestHeaderMessage.getBytes(tmpMB);
 
695
                ByteChunk bc = tmpMB.getByteChunk();
 
696
                vMB = headers.addValue(bc.getBuffer(),
 
697
                        bc.getStart(), bc.getLength());
 
698
            }
 
699
 
 
700
            requestHeaderMessage.getBytes(vMB);
 
701
 
 
702
            if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
 
703
                    (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
 
704
                // just read the content-length header, so set it
 
705
                long cl = vMB.getLong();
 
706
                if(cl < Integer.MAX_VALUE)
 
707
                    request.setContentLength( (int)cl );
 
708
            } else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
 
709
                    (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
 
710
                // just read the content-type header, so set it
 
711
                ByteChunk bchunk = vMB.getByteChunk();
 
712
                request.contentType().setBytes(bchunk.getBytes(),
 
713
                        bchunk.getOffset(),
 
714
                        bchunk.getLength());
 
715
            }
 
716
        }
 
717
 
 
718
        // Decode extra attributes
 
719
        boolean secret = false;
 
720
        byte attributeCode;
 
721
        while ((attributeCode = requestHeaderMessage.getByte())
 
722
                != Constants.SC_A_ARE_DONE) {
 
723
 
 
724
            switch (attributeCode) {
 
725
 
 
726
            case Constants.SC_A_REQ_ATTRIBUTE :
 
727
                requestHeaderMessage.getBytes(tmpMB);
 
728
                String n = tmpMB.toString();
 
729
                requestHeaderMessage.getBytes(tmpMB);
 
730
                String v = tmpMB.toString();
 
731
                /*
 
732
                 * AJP13 misses to forward the remotePort.
 
733
                 * Allow the AJP connector to add this info via
 
734
                 * a private request attribute.
 
735
                 * We will accept the forwarded data as the remote port,
 
736
                 * and remove it from the public list of request attributes.
 
737
                 */
 
738
                if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) {
 
739
                    try {
 
740
                        request.setRemotePort(Integer.parseInt(v));
 
741
                    } catch (NumberFormatException nfe) {
 
742
                    }
 
743
                } else {
 
744
                    request.setAttribute(n, v );
 
745
                }
 
746
                break;
 
747
 
 
748
            case Constants.SC_A_CONTEXT :
 
749
                requestHeaderMessage.getBytes(tmpMB);
 
750
                // nothing
 
751
                break;
 
752
 
 
753
            case Constants.SC_A_SERVLET_PATH :
 
754
                requestHeaderMessage.getBytes(tmpMB);
 
755
                // nothing
 
756
                break;
 
757
 
 
758
            case Constants.SC_A_REMOTE_USER :
 
759
                if (tomcatAuthentication) {
 
760
                    // ignore server
 
761
                    requestHeaderMessage.getBytes(tmpMB);
 
762
                } else {
 
763
                    requestHeaderMessage.getBytes(request.getRemoteUser());
 
764
                }
 
765
                break;
 
766
 
 
767
            case Constants.SC_A_AUTH_TYPE :
 
768
                if (tomcatAuthentication) {
 
769
                    // ignore server
 
770
                    requestHeaderMessage.getBytes(tmpMB);
 
771
                } else {
 
772
                    requestHeaderMessage.getBytes(request.getAuthType());
 
773
                }
 
774
                break;
 
775
 
 
776
            case Constants.SC_A_QUERY_STRING :
 
777
                requestHeaderMessage.getBytes(request.queryString());
 
778
                break;
 
779
 
 
780
            case Constants.SC_A_JVM_ROUTE :
 
781
                requestHeaderMessage.getBytes(request.instanceId());
 
782
                break;
 
783
 
 
784
            case Constants.SC_A_SSL_CERT :
 
785
                request.scheme().setString("https");
 
786
                // SSL certificate extraction is lazy, moved to JkCoyoteHandler
 
787
                requestHeaderMessage.getBytes(certificates);
 
788
                break;
 
789
 
 
790
            case Constants.SC_A_SSL_CIPHER :
 
791
                request.scheme().setString("https");
 
792
                requestHeaderMessage.getBytes(tmpMB);
 
793
                request.setAttribute(JIoEndpoint.CIPHER_SUITE_KEY,
 
794
                                     tmpMB.toString());
 
795
                break;
 
796
 
 
797
            case Constants.SC_A_SSL_SESSION :
 
798
                request.scheme().setString("https");
 
799
                requestHeaderMessage.getBytes(tmpMB);
 
800
                request.setAttribute(JIoEndpoint.SESSION_ID_KEY,
 
801
                                     tmpMB.toString());
 
802
                break;
 
803
 
 
804
            case Constants.SC_A_SSL_KEY_SIZE :
 
805
                request.setAttribute(JIoEndpoint.KEY_SIZE_KEY,
 
806
                                     new Integer(requestHeaderMessage.getInt()));
 
807
                break;
 
808
 
 
809
            case Constants.SC_A_STORED_METHOD:
 
810
                requestHeaderMessage.getBytes(request.method());
 
811
                break;
 
812
 
 
813
            case Constants.SC_A_SECRET:
 
814
                requestHeaderMessage.getBytes(tmpMB);
 
815
                if (requiredSecret != null) {
 
816
                    secret = true;
 
817
                    if (!tmpMB.equals(requiredSecret)) {
 
818
                        response.setStatus(403);
 
819
                        error = true;
 
820
                    }
 
821
                }
 
822
                break;
 
823
 
 
824
            default:
 
825
                // Ignore unknown attribute for backward compatibility
 
826
                break;
 
827
 
 
828
            }
 
829
 
 
830
        }
 
831
 
 
832
        // Check if secret was submitted if required
 
833
        if ((requiredSecret != null) && !secret) {
 
834
            response.setStatus(403);
 
835
            error = true;
 
836
        }
 
837
 
 
838
        // Check for a full URI (including protocol://host:port/)
 
839
        ByteChunk uriBC = request.requestURI().getByteChunk();
 
840
        if (uriBC.startsWithIgnoreCase("http", 0)) {
 
841
 
 
842
            int pos = uriBC.indexOf("://", 0, 3, 4);
 
843
            int uriBCStart = uriBC.getStart();
 
844
            int slashPos = -1;
 
845
            if (pos != -1) {
 
846
                byte[] uriB = uriBC.getBytes();
 
847
                slashPos = uriBC.indexOf('/', pos + 3);
 
848
                if (slashPos == -1) {
 
849
                    slashPos = uriBC.getLength();
 
850
                    // Set URI as "/"
 
851
                    request.requestURI().setBytes
 
852
                        (uriB, uriBCStart + pos + 1, 1);
 
853
                } else {
 
854
                    request.requestURI().setBytes
 
855
                        (uriB, uriBCStart + slashPos,
 
856
                         uriBC.getLength() - slashPos);
 
857
                }
 
858
                MessageBytes hostMB = headers.setValue("host");
 
859
                hostMB.setBytes(uriB, uriBCStart + pos + 3,
 
860
                                slashPos - pos - 3);
 
861
            }
 
862
 
 
863
        }
 
864
 
 
865
        MessageBytes valueMB = request.getMimeHeaders().getValue("host");
 
866
        parseHost(valueMB);
 
867
 
 
868
    }
 
869
 
 
870
 
 
871
    /**
 
872
     * Parse host.
 
873
     */
 
874
    public void parseHost(MessageBytes valueMB) {
 
875
 
 
876
        if (valueMB == null || (valueMB != null && valueMB.isNull()) ) {
 
877
            // HTTP/1.0
 
878
            request.setServerPort(request.getLocalPort());
 
879
            try {
 
880
                request.serverName().duplicate(request.localName());
 
881
            } catch (IOException e) {
 
882
                response.setStatus(400);
 
883
                error = true;
 
884
            }
 
885
            return;
 
886
        }
 
887
 
 
888
        ByteChunk valueBC = valueMB.getByteChunk();
 
889
        byte[] valueB = valueBC.getBytes();
 
890
        int valueL = valueBC.getLength();
 
891
        int valueS = valueBC.getStart();
 
892
        int colonPos = -1;
 
893
        if (hostNameC.length < valueL) {
 
894
            hostNameC = new char[valueL];
 
895
        }
 
896
 
 
897
        boolean ipv6 = (valueB[valueS] == '[');
 
898
        boolean bracketClosed = false;
 
899
        for (int i = 0; i < valueL; i++) {
 
900
            char b = (char) valueB[i + valueS];
 
901
            hostNameC[i] = b;
 
902
            if (b == ']') {
 
903
                bracketClosed = true;
 
904
            } else if (b == ':') {
 
905
                if (!ipv6 || bracketClosed) {
 
906
                    colonPos = i;
 
907
                    break;
 
908
                }
 
909
            }
 
910
        }
 
911
 
 
912
        if (colonPos < 0) {
 
913
            if (request.scheme().equalsIgnoreCase("https")) {
 
914
                // 443 - Default HTTPS port
 
915
                request.setServerPort(443);
 
916
            } else {
 
917
                // 80 - Default HTTTP port
 
918
                request.setServerPort(80);
 
919
            }
 
920
            request.serverName().setChars(hostNameC, 0, valueL);
 
921
        } else {
 
922
 
 
923
            request.serverName().setChars(hostNameC, 0, colonPos);
 
924
 
 
925
            int port = 0;
 
926
            int mult = 1;
 
927
            for (int i = valueL - 1; i > colonPos; i--) {
 
928
                int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
 
929
                if (charValue == -1) {
 
930
                    // Invalid character
 
931
                    error = true;
 
932
                    // 400 - Bad request
 
933
                    response.setStatus(400);
 
934
                    break;
 
935
                }
 
936
                port = port + (charValue * mult);
 
937
                mult = 10 * mult;
 
938
            }
 
939
            request.setServerPort(port);
 
940
 
 
941
        }
 
942
 
 
943
    }
 
944
 
 
945
 
 
946
    /**
 
947
     * When committing the response, we have to validate the set of headers, as
 
948
     * well as setup the response filters.
 
949
     */
 
950
    protected void prepareResponse()
 
951
        throws IOException {
 
952
 
 
953
        response.setCommitted(true);
 
954
 
 
955
        responseHeaderMessage.reset();
 
956
        responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
 
957
 
 
958
        // HTTP header contents
 
959
        responseHeaderMessage.appendInt(response.getStatus());
 
960
        String message = null;
 
961
        if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER &&
 
962
                HttpMessages.isSafeInHttpHeader(response.getMessage())) {
 
963
            message = response.getMessage();
 
964
        }
 
965
        if (message == null){
 
966
            message = HttpMessages.getMessage(response.getStatus());
 
967
        }
 
968
        if (message == null) {
 
969
            // mod_jk + httpd 2.x fails with a null status message - bug 45026
 
970
            message = Integer.toString(response.getStatus());
 
971
        }
 
972
        tmpMB.setString(message);
 
973
        responseHeaderMessage.appendBytes(tmpMB);
 
974
 
 
975
        // Special headers
 
976
        MimeHeaders headers = response.getMimeHeaders();
 
977
        String contentType = response.getContentType();
 
978
        if (contentType != null) {
 
979
            headers.setValue("Content-Type").setString(contentType);
 
980
        }
 
981
        String contentLanguage = response.getContentLanguage();
 
982
        if (contentLanguage != null) {
 
983
            headers.setValue("Content-Language").setString(contentLanguage);
 
984
        }
 
985
        long contentLength = response.getContentLengthLong();
 
986
        if (contentLength >= 0) {
 
987
            headers.setValue("Content-Length").setLong(contentLength);
 
988
        }
 
989
 
 
990
        // Other headers
 
991
        int numHeaders = headers.size();
 
992
        responseHeaderMessage.appendInt(numHeaders);
 
993
        for (int i = 0; i < numHeaders; i++) {
 
994
            MessageBytes hN = headers.getName(i);
 
995
            int hC = Constants.getResponseAjpIndex(hN.toString());
 
996
            if (hC > 0) {
 
997
                responseHeaderMessage.appendInt(hC);
 
998
            }
 
999
            else {
 
1000
                responseHeaderMessage.appendBytes(hN);
 
1001
            }
 
1002
            MessageBytes hV=headers.getValue(i);
 
1003
            responseHeaderMessage.appendBytes(hV);
 
1004
        }
 
1005
 
 
1006
        // Write to buffer
 
1007
        responseHeaderMessage.end();
 
1008
        output.write(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
 
1009
 
 
1010
    }
 
1011
 
 
1012
 
 
1013
    /**
 
1014
     * Finish AJP response.
 
1015
     */
 
1016
    protected void finish()
 
1017
        throws IOException {
 
1018
 
 
1019
        if (!response.isCommitted()) {
 
1020
            // Validate and write response headers
 
1021
            try {
 
1022
                prepareResponse();
 
1023
            } catch (IOException e) {
 
1024
                // Set error flag
 
1025
                error = true;
 
1026
            }
 
1027
        }
 
1028
 
 
1029
        if (finished)
 
1030
            return;
 
1031
 
 
1032
        finished = true;
 
1033
 
 
1034
        // Add the end message
 
1035
        output.write(endMessageArray);
 
1036
 
 
1037
    }
 
1038
 
 
1039
 
 
1040
    /**
 
1041
     * Read at least the specified amount of bytes, and place them
 
1042
     * in the input buffer.
 
1043
     */
 
1044
    protected boolean read(byte[] buf, int pos, int n)
 
1045
        throws IOException {
 
1046
 
 
1047
        int read = 0;
 
1048
        int res = 0;
 
1049
        while (read < n) {
 
1050
            res = input.read(buf, read + pos, n - read);
 
1051
            if (res > 0) {
 
1052
                read += res;
 
1053
            } else {
 
1054
                throw new IOException(sm.getString("ajpprotocol.failedread"));
 
1055
            }
 
1056
        }
 
1057
        
 
1058
        return true;
 
1059
 
 
1060
    }
 
1061
 
 
1062
 
 
1063
    /** Receive a chunk of data. Called to implement the
 
1064
     *  'special' packet in ajp13 and to receive the data
 
1065
     *  after we send a GET_BODY packet
 
1066
     */
 
1067
    public boolean receive() throws IOException {
 
1068
 
 
1069
        first = false;
 
1070
        bodyMessage.reset();
 
1071
        readMessage(bodyMessage);
 
1072
 
 
1073
        // No data received.
 
1074
        if (bodyMessage.getLen() == 0) {
 
1075
            // just the header
 
1076
            // Don't mark 'end of stream' for the first chunk.
 
1077
            return false;
 
1078
        }
 
1079
        int blen = bodyMessage.peekInt();
 
1080
        if (blen == 0) {
 
1081
            return false;
 
1082
        }
 
1083
 
 
1084
        bodyMessage.getBytes(bodyBytes);
 
1085
        empty = false;
 
1086
        return true;
 
1087
    }
 
1088
 
 
1089
    /**
 
1090
     * Get more request body data from the web server and store it in the
 
1091
     * internal buffer.
 
1092
     *
 
1093
     * @return true if there is more data, false if not.
 
1094
     */
 
1095
    private boolean refillReadBuffer() throws IOException {
 
1096
        // If the server returns an empty packet, assume that that end of
 
1097
        // the stream has been reached (yuck -- fix protocol??).
 
1098
        // FORM support
 
1099
        if (replay) {
 
1100
            endOfStream = true; // we've read everything there is
 
1101
        }
 
1102
        if (endOfStream) {
 
1103
            return false;
 
1104
        }
 
1105
 
 
1106
        // Request more data immediately
 
1107
        output.write(getBodyMessageArray);
 
1108
 
 
1109
        boolean moreData = receive();
 
1110
        if( !moreData ) {
 
1111
            endOfStream = true;
 
1112
        }
 
1113
        return moreData;
 
1114
    }
 
1115
 
 
1116
 
 
1117
    /**
 
1118
     * Read an AJP message.
 
1119
     *
 
1120
     * @return true if the message has been read, false if the short read
 
1121
     *         didn't return anything
 
1122
     * @throws IOException any other failure, including incomplete reads
 
1123
     */
 
1124
    protected boolean readMessage(AjpMessage message)
 
1125
        throws IOException {
 
1126
 
 
1127
        byte[] buf = message.getBuffer();
 
1128
 
 
1129
        read(buf, 0, message.getHeaderLength());
 
1130
 
 
1131
        message.processHeader();
 
1132
        read(buf, message.getHeaderLength(), message.getLen());
 
1133
 
 
1134
        return true;
 
1135
 
 
1136
    }
 
1137
 
 
1138
 
 
1139
    /**
 
1140
     * Recycle the processor.
 
1141
     */
 
1142
    public void recycle() {
 
1143
 
 
1144
        // Recycle Request object
 
1145
        first = true;
 
1146
        endOfStream = false;
 
1147
        empty = true;
 
1148
        replay = false;
 
1149
        finished = false;
 
1150
        request.recycle();
 
1151
        response.recycle();
 
1152
        certificates.recycle();
 
1153
 
 
1154
    }
 
1155
 
 
1156
 
 
1157
    /**
 
1158
     * Callback to write data from the buffer.
 
1159
     */
 
1160
    protected void flush()
 
1161
        throws IOException {
 
1162
        // Send the flush message
 
1163
        output.write(flushMessageArray);
 
1164
    }
 
1165
 
 
1166
 
 
1167
    // ------------------------------------- InputStreamInputBuffer Inner Class
 
1168
 
 
1169
 
 
1170
    /**
 
1171
     * This class is an input buffer which will read its data from an input
 
1172
     * stream.
 
1173
     */
 
1174
    protected class SocketInputBuffer
 
1175
        implements InputBuffer {
 
1176
 
 
1177
 
 
1178
        /**
 
1179
         * Read bytes into the specified chunk.
 
1180
         */
 
1181
        public int doRead(ByteChunk chunk, Request req )
 
1182
            throws IOException {
 
1183
 
 
1184
            if (endOfStream) {
 
1185
                return -1;
 
1186
            }
 
1187
            if (first && req.getContentLengthLong() > 0) {
 
1188
                // Handle special first-body-chunk
 
1189
                if (!receive()) {
 
1190
                    return 0;
 
1191
                }
 
1192
            } else if (empty) {
 
1193
                if (!refillReadBuffer()) {
 
1194
                    return -1;
 
1195
                }
 
1196
            }
 
1197
            ByteChunk bc = bodyBytes.getByteChunk();
 
1198
            chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength());
 
1199
            empty = true;
 
1200
            return chunk.getLength();
 
1201
 
 
1202
        }
 
1203
 
 
1204
    }
 
1205
 
 
1206
 
 
1207
    // ----------------------------------- OutputStreamOutputBuffer Inner Class
 
1208
 
 
1209
 
 
1210
    /**
 
1211
     * This class is an output buffer which will write data to an output
 
1212
     * stream.
 
1213
     */
 
1214
    protected class SocketOutputBuffer
 
1215
        implements OutputBuffer {
 
1216
 
 
1217
 
 
1218
        /**
 
1219
         * Write chunk.
 
1220
         */
 
1221
        public int doWrite(ByteChunk chunk, Response res)
 
1222
            throws IOException {
 
1223
 
 
1224
            if (!response.isCommitted()) {
 
1225
                // Validate and write response headers
 
1226
                try {
 
1227
                    prepareResponse();
 
1228
                } catch (IOException e) {
 
1229
                    // Set error flag
 
1230
                    error = true;
 
1231
                }
 
1232
            }
 
1233
 
 
1234
            int len = chunk.getLength();
 
1235
            // 4 - hardcoded, byte[] marshalling overhead
 
1236
            // Adjust allowed size if packetSize != default (Constants.MAX_PACKET_SIZE)
 
1237
            int chunkSize = Constants.MAX_SEND_SIZE + packetSize - Constants.MAX_PACKET_SIZE;
 
1238
            int off = 0;
 
1239
            while (len > 0) {
 
1240
                int thisTime = len;
 
1241
                if (thisTime > chunkSize) {
 
1242
                    thisTime = chunkSize;
 
1243
                }
 
1244
                len -= thisTime;
 
1245
                responseHeaderMessage.reset();
 
1246
                responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
 
1247
                responseHeaderMessage.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime);
 
1248
                responseHeaderMessage.end();
 
1249
                output.write(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
 
1250
 
 
1251
                off += thisTime;
 
1252
            }
 
1253
 
 
1254
            return chunk.getLength();
 
1255
 
 
1256
        }
 
1257
 
 
1258
 
 
1259
    }
 
1260
 
 
1261
 
 
1262
}