001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http.impl.conn; 029 030import java.io.IOException; 031 032import org.apache.commons.logging.Log; 033import org.apache.commons.logging.LogFactory; 034import org.apache.http.HttpException; 035import org.apache.http.HttpResponse; 036import org.apache.http.HttpResponseFactory; 037import org.apache.http.NoHttpResponseException; 038import org.apache.http.ProtocolException; 039import org.apache.http.StatusLine; 040import org.apache.http.config.MessageConstraints; 041import org.apache.http.impl.DefaultHttpResponseFactory; 042import org.apache.http.impl.io.AbstractMessageParser; 043import org.apache.http.io.SessionInputBuffer; 044import org.apache.http.message.LineParser; 045import org.apache.http.message.ParserCursor; 046import org.apache.http.params.HttpParams; 047import org.apache.http.util.Args; 048import org.apache.http.util.CharArrayBuffer; 049 050/** 051 * Lenient HTTP response parser implementation that can skip malformed data until 052 * a valid HTTP response message head is encountered. 053 * 054 * @since 4.2 055 */ 056@SuppressWarnings("deprecation") 057public class DefaultHttpResponseParser extends AbstractMessageParser<HttpResponse> { 058 059 private final Log log = LogFactory.getLog(getClass()); 060 061 private final HttpResponseFactory responseFactory; 062 private final CharArrayBuffer lineBuf; 063 064 /** 065 * @deprecated (4.3) use {@link DefaultHttpResponseParser#DefaultHttpResponseParser( 066 * SessionInputBuffer, LineParser, HttpResponseFactory, MessageConstraints)} 067 */ 068 @Deprecated 069 public DefaultHttpResponseParser( 070 final SessionInputBuffer buffer, 071 final LineParser parser, 072 final HttpResponseFactory responseFactory, 073 final HttpParams params) { 074 super(buffer, parser, params); 075 Args.notNull(responseFactory, "Response factory"); 076 this.responseFactory = responseFactory; 077 this.lineBuf = new CharArrayBuffer(128); 078 } 079 080 /** 081 * Creates new instance of DefaultHttpResponseParser. 082 * 083 * @param buffer the session input buffer. 084 * @param lineParser the line parser. If {@code null} 085 * {@link org.apache.http.message.BasicLineParser#INSTANCE} will be used. 086 * @param responseFactory HTTP response factory. If {@code null} 087 * {@link DefaultHttpResponseFactory#INSTANCE} will be used. 088 * @param constraints the message constraints. If {@code null} 089 * {@link MessageConstraints#DEFAULT} will be used. 090 * 091 * @since 4.3 092 */ 093 public DefaultHttpResponseParser( 094 final SessionInputBuffer buffer, 095 final LineParser lineParser, 096 final HttpResponseFactory responseFactory, 097 final MessageConstraints constraints) { 098 super(buffer, lineParser, constraints); 099 this.responseFactory = responseFactory != null ? responseFactory : 100 DefaultHttpResponseFactory.INSTANCE; 101 this.lineBuf = new CharArrayBuffer(128); 102 } 103 104 /** 105 * Creates new instance of DefaultHttpResponseParser. 106 * 107 * @param buffer the session input buffer. 108 * @param constraints the message constraints. If {@code null} 109 * {@link MessageConstraints#DEFAULT} will be used. 110 * 111 * @since 4.3 112 */ 113 public DefaultHttpResponseParser( 114 final SessionInputBuffer buffer, final MessageConstraints constraints) { 115 this(buffer, null, null, constraints); 116 } 117 118 /** 119 * Creates new instance of DefaultHttpResponseParser. 120 * 121 * @param buffer the session input buffer. 122 * 123 * @since 4.3 124 */ 125 public DefaultHttpResponseParser(final SessionInputBuffer buffer) { 126 this(buffer, null, null, MessageConstraints.DEFAULT); 127 } 128 129 @Override 130 protected HttpResponse parseHead( 131 final SessionInputBuffer sessionBuffer) throws IOException, HttpException { 132 //read out the HTTP status string 133 int count = 0; 134 ParserCursor cursor = null; 135 do { 136 // clear the buffer 137 this.lineBuf.clear(); 138 final int i = sessionBuffer.readLine(this.lineBuf); 139 if (i == -1 && count == 0) { 140 // The server just dropped connection on us 141 throw new NoHttpResponseException("The target server failed to respond"); 142 } 143 cursor = new ParserCursor(0, this.lineBuf.length()); 144 if (lineParser.hasProtocolVersion(this.lineBuf, cursor)) { 145 // Got one 146 break; 147 } else if (i == -1 || reject(this.lineBuf, count)) { 148 // Giving up 149 throw new ProtocolException("The server failed to respond with a " + 150 "valid HTTP response"); 151 } 152 if (this.log.isDebugEnabled()) { 153 this.log.debug("Garbage in response: " + this.lineBuf.toString()); 154 } 155 count++; 156 } while(true); 157 //create the status line from the status string 158 final StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, cursor); 159 return this.responseFactory.newHttpResponse(statusline, null); 160 } 161 162 protected boolean reject(final CharArrayBuffer line, final int count) { 163 return false; 164 } 165 166}