Как проанализировать стандартный HTTP-ответ none?
Мне очень трудно понять, как анализировать стандартный HTTP-ответ none.
Стандартный ответ none содержит ICY 200 OK
вместо HTTP 200 OK
. Вот пример URL-адреса, который отправляет стандартный HTTP-ответ none.http://50.117.121.162:80
Начиная с Android 4.4 HttpURLConnection больше не будет работать с этими стандартными ответами none. Я пробовал использовать HttpClient от Apache, но он не работает из-за стандартного HTTP-ответа none. Я тогда попробовал следуя руководству по добавлениюпользовательского парсера ответов , но Android, похоже, не имеет всех классов, необходимых для этого.
Я действительно изо всех сил пытаюсь найти решение. Возможно, изменить стандартный ответ none, прежде чем он будет проанализирован с помощью HttpClient или HttpURLConnection, может сработать, но я не уверен, что это вообще возможно...
Любая помощь будет весьма признательна.6 ответов:
После долгих поисков небольшой / облегченной клиентской библиотеки http я наткнулся на этот порт apachehttpclient для android . Библиотека обеспечивала полную поддержку http-соединений. Затем я просто изменил исходный код, в частности BasicLineParser, чтобы заменить ICY на HTTP / 1.0.
У меня была аналогичная проблема с KitKat и я успешно использовал два класса, найденных здесь для http post. Они невероятно просты в использовании,и вы можете легко изменить параметры протокола.
Есть еще одно решение этой проблемы в Android 4.4, но оно требует использования Apache HttpClient. Это основано на возможности предоставления пользовательского парсера ответа в Apache Http engine, который может изменить ICY 200 OK на HTTP/1.0 200 OK. Это основано на общей идее, представленной в:
Http://hc.apache.org/httpcomponents-client-4.2.x/tutorial/html/advanced.html
Я успешно использовал следующий код.
public class IcyClientConnection extends DefaultClientConnection{ @Override protected HttpMessageParser createResponseParser(SessionInputBuffer buffer, HttpResponseFactory responseFactory, HttpParams params) { return new IcyHttpResponseParser( buffer, new BasicLineParser (), responseFactory, params); } } public class IcyClientConnectionOperator extends DefaultClientConnectionOperator { public IcyClientConnectionOperator(SchemeRegistry schemes) { super(schemes); } @Override public OperatedClientConnection createConnection() { return new IcyClientConnection(); } } public class IcyClientConnManager extends SingleClientConnManager { public IcyClientConnManager(HttpParams params, SchemeRegistry schreg) { super(params, schreg); } @Override protected ClientConnectionOperator createConnectionOperator( SchemeRegistry schreg) { return new IcyClientConnectionOperator(schreg); } }
Теперь вы должны расширить синтаксический анализатор, используемый по умолчанию и добавьте код, который изменит неправильное воспроизведение сервера на правильное. Обычно код блокируется на
hasProtocolVersion
.public class IcyHttpResponseParser extends DefaultResponseParser{ private CharArrayBuffer icyLineBuf; private int icyMaxGarbageLines = 1000; private final HttpResponseFactory icyResponseFactory; public IcyHttpResponseParser(SessionInputBuffer buffer, LineParser parser, HttpResponseFactory responseFactory, HttpParams params) { super(buffer, parser, responseFactory, params); this.icyLineBuf = new CharArrayBuffer(128); icyResponseFactory = responseFactory; } @Override protected HttpMessage parseHead(SessionInputBuffer sessionBuffer) throws IOException, HttpException { int count = 0; ParserCursor cursor = null; do { // clear the buffer this.icyLineBuf.clear(); final int i = sessionBuffer.readLine(this.icyLineBuf); //look for ICY and change to HTTP to provide compatibility with non standard shoutcast servers String tmp = icyLineBuf.substring(0, this.icyLineBuf.length()); if(tmp.contains("ICY ")){ tmp = tmp.replace("ICY", "HTTP/1.0"); } //copy this.icyLineBuf = new CharArrayBuffer(128); System.arraycopy(tmp.toCharArray(), 0, icyLineBuf.buffer(), 0, tmp.length()); icyLineBuf.setLength( tmp.length()); if (i == -1 && count == 0) { // The server just dropped connection on us throw new NoHttpResponseException("The target server failed to respond"); } cursor = new ParserCursor(0, this.icyLineBuf.length()); if (lineParser.hasProtocolVersion(this.icyLineBuf, cursor)) { // Got one break; } else if (i == -1 || count >= this.icyMaxGarbageLines) { // Giving up throw new ProtocolException("The server failed to respond with a " + "valid HTTP response"); } //if (this.log.isDebugEnabled()) { // this.log.debug("Garbage in response: " + this.lineBuf.toString()); // } count++; } while(true); //create the status line from the status string final StatusLine statusline = lineParser.parseStatusLine(this.icyLineBuf, cursor); return this.icyResponseFactory.newHttpResponse(statusline, null); } }
Подключите HttpClient:
Это все еще тестируется, но первоначальные результаты многообещающи.Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80); Scheme ftp = new Scheme("ftp", PlainSocketFactory.getSocketFactory(), 21); SchemeRegistry sr = new SchemeRegistry(); sr.register(http); sr.register(ftp); HttpClient httpClient = new DefaultHttpClient(new IcyClientConnManager(params, sr), params);
Спасибо @Михаил м, вы даже можете сделать его проще путем создания подклассов BasicLineParser вместо наследованием DefaultResponseParser.
Чтобы использовать его:
IcyGetRequest request = new IcyGetRequest(urlStr); HttpResponse response = request.get(); int responseCode = response.getStatusLine().getStatusCode();
Создайте runnable, который создает Socket proxy, тогда вы сможете ответить с HTTP / 1.0 вместо ICY , а затем просто подключитесь к этому локальному Socket proxy с вашим плеером
Здесь модификация решения изMichal M на случай, если вам не нравится создавать множество подклассов только для настройки уже доступных классов
HttpClient
.final SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); HttpClient httpClient = new DefaultHttpClient() { @Override protected ClientConnectionManager createClientConnectionManager() { return new SingleClientConnManager(getParams(), schemeRegistry) { @Override protected ClientConnectionOperator createConnectionOperator(SchemeRegistry schreg) { return new DefaultClientConnectionOperator(schreg) { @Override public OperatedClientConnection createConnection() { return new DefaultClientConnection() { @Override protected HttpMessageParser createResponseParser(SessionInputBuffer buffer, HttpResponseFactory responseFactory, HttpParams params) { return new IcyHttpResponseParser(buffer, new BasicLineParser(), responseFactory, params); } }; } }; } }; } };
Вероятно, есть способ получить
SchemeRegistry
устаревший, если бы можно было каким-то образом получить доступ из классаDefaultHttpClient
.