DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=3784>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=3784

Long URLs cause ArrayIndexOutOfBoundsException

           Summary: Long URLs cause ArrayIndexOutOfBoundsException
           Product: Tomcat 3
           Version: 3.2.3 Final
          Platform: All
        OS/Version: Other
            Status: NEW
          Severity: Major
          Priority: Other
         Component: Connectors
        AssignedTo: [EMAIL PROTECTED]
        ReportedBy: [EMAIL PROTECTED]


I have discovered and fixed several bugs in jakarta-tomcat-3.2.3, all in the
HttpRequestAdapter.java source file.

The bugs manifest themselves when the URI for the HTTP request (including the
request parameter list) exceeds 2048 characters.  This prevents Tomcat from
being useful for sites which have forms with lots of fields, for example, in
which case the sumission of the form could cause a "POST" or "GET" request with
a lot of parameters tacked onto the URI.  This causes an
ArrayIndexOutOfBoundsException due to badly written code in the
src/org/apache/tomcat/service/http/HttpRequestAdapter.java.  I have included my
corrected versions of the affected methods from this file, and have tested it
with URIs over 12,000 characters in length.  There are two methods affected:
readNextRequest() and readHeaders().

Please integrate these changes into the next release of jakarta-tomcat, so that
everyone can benefit from them.

Thanks for the great software!!!
Ron Cemer 

    public void readNextRequest(Response response) throws IOException {

        // Odd, but works: we use the ServletInputStream, which uses doRead.
        // We do implement doRead in Http protocol to return from the input
        // stream - it works for the normal body but also for the HTTP
        // head. The limit is set after ( and if ) we have a content-length.
        
/// Replaced this line with the code block below to support requests of
/// arbitrary lengths.  - Ron Cemer
///
count = in.readLine(buf, 0, buf.length);
        count = 0;
        while (true) {
            int len = buf.length-count;
            if (len > 0) {
                len = in.readLine(buf, count, len);
                if ( (len == -1) && (count == 0) ) {
                    count = -1;
                    break;
                }
                count += len;
                if (len == 0 || buf[count-1] == '\n') {
                    break;
                }
            }
                // overflowed buffer, so temporarily expand and continue
            byte[] tmp = new byte[buf.length * 2];
            System.arraycopy(buf, 0, tmp, 0, buf.length);
            buf = tmp;
        }
/// End of replacement code.

        if (count < 0 ) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }
        
        processRequestLine(response  );

        // for 0.9, we don't have headers!
        if (protocol!=null) { // all HTTP versions with protocol also have headers ( 
0.9
has no HTTP/0.9 !)
            readHeaders( headers, in  );
        }

        // XXX
        // detect for real whether or not we have more requests
        // coming
        moreRequests = false;   
    }


    /**
     * Reads header fields from the specified servlet input stream until
     * a blank line is encountered.
     * @param in the servlet input stream
     * @exception IllegalArgumentException if the header format was invalid 
     * @exception IOException if an I/O error has occurred
     */
    public void readHeaders( MimeHeaders headers, ServletInputStream in ) 
throws IOException {
        // use pre-allocated buffer if possible
        off = count; // where the request line ended
        
        while (true) {
            int start = off;

            while (true) {
                int len = buf.length - off;

                if (len > 0) {
                    len = in.readLine(buf, off, len);
                    if (len == -1) {
                        String msg =
                            sm1.getString("mimeHeader.connection.ioe");

                        throw new IOException (msg);
                    }
///
        }

/// This code should be WITHIN the second "while (true)".  - Ron Cemer
                    off += len;

                    if (len == 0 || buf[off-1] == '\n') {
                        break;
                    }
///
                }

                // overflowed buffer, so temporarily expand and continue

                // XXX DOS - if the length is too big - stop and throw exception
                byte[] tmp = new byte[buf.length * 2];

                System.arraycopy(buf, 0, tmp, 0, buf.length);
                buf = tmp;
            }

            // strip off trailing "\r\n"
///
    if (--off > start && buf[off-1] == '\r') {
///
        --off;
///
    }
/// This is a less error-prone way of accomplishing the task.  - Ron Cemer
            if ( (off > start) && (buf[off-1] == '\n') ) {
                off--;
                if ( (off > start) && (buf[off-1] == '\r') )
                    off--;
            }

            if (off == start) {
                break;
            }
            
            // XXX this does not currently handle headers which
            // are folded to take more than one line.
            MimeHeaderField mhf=headers.putHeader();
            if( ! parseHeaderFiled(mhf, buf, start, off - start) ) {
                // error parsing header
                return;
            }
        }
    }

Reply via email to