/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.plugin.docker.client.connection; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /** * @author andrew00x */ public class UnixSocketDockerResponse implements DockerResponse { private static final InputStream EMPTY = new InputStream() { @Override public int read() throws IOException { return -1; } }; private final InputStream rawData; private InputStream data; private String[] headersFields; private int status; UnixSocketDockerResponse(InputStream input) { rawData = input; status = -1; } @Override public int getStatus() throws IOException { if (status != -1) { return status; } getInputStream(); final String statusLine = headersFields[0]; if (statusLine.startsWith("HTTP/1.")) { int startCode = statusLine.indexOf(' '); if (startCode > 0) { int endCode = statusLine.indexOf(' ', startCode + 1); if (endCode < 0) { endCode = statusLine.length(); } try { return status = Integer.parseInt(statusLine.substring(startCode + 1, endCode)); } catch (NumberFormatException ignored) { } } } return -1; } @Override public int getContentLength() throws IOException { final String header = getHeader("Content-Length"); if (header != null) { try { return Integer.parseInt(header); } catch (NumberFormatException ignored) { } } return -1; } @Override public String getContentType() throws IOException { return getHeader("Content-Type"); } @Override public String getHeader(String name) throws IOException { getInputStream(); final String lowerCaseName = name.toLowerCase(); for (String field : headersFields) { if (field.toLowerCase().startsWith(lowerCaseName)) { int colonPos = field.indexOf(':'); if (colonPos > 0) { return field.substring(colonPos + 1).trim(); } } } return null; } @Override public String[] getHeaders(String name) throws IOException { getInputStream(); final String lowerCaseName = name.toLowerCase(); final List<String> headers = new ArrayList<>(4); for (String field : headersFields) { if (field.toLowerCase().startsWith(lowerCaseName)) { int colonPos = field.indexOf(':'); if (colonPos > 0) { headers.add(field.substring(colonPos + 1).trim()); } } } return headers.toArray(new String[headers.size()]); } @Override public synchronized InputStream getInputStream() throws IOException { if (this.headersFields != null) { // already parsed return data; } final StringBuilder lineBuf = new StringBuilder(); for (int i = 0; i < 8; i++) { int c = rawData.read(); if (c == -1) { break; } lineBuf.append((char)c); } if (!lineBuf.toString().startsWith("HTTP/1.")) { throw new IOException("Invalid status line of HTTP response from docker API"); } final List<String> headerFields = new ArrayList<>(4); for (; ; ) { int c = rawData.read(); if (c == -1) { throw new IOException("Unexpected end of file from docker API"); } else if (c == '\n') { if (lineBuf.length() == 0) { break; } headerFields.add(lineBuf.toString()); lineBuf.setLength(0); } else if (c != '\r') { lineBuf.append((char)c); } } this.headersFields = headerFields.toArray(new String[headerFields.size()]); final int contentLength = getContentLength(); if (contentLength == 0) { return data = EMPTY; } if (contentLength > 0) { return data = new LimitedInputStream(rawData, contentLength); } return data = "chunked".equals(getHeader("Transfer-Encoding")) ? new ChunkedInputStream(rawData) : rawData; } }