2015년 9월 22일 화요일

OkHttp 이해하기 - 6

첫 HttpEngine 생성시는 OkHttpClient와 Request와 forWebSocket의 여부를 참조합니다. forWebSocket은 HTTP 요청이 synchronous call(execute 함수 사용)인 경우에는 항상 false입니다. AsyncCall 을 사용한 asynchronous call(enqueue 함수 사용)인 경우에는 파라메타로 forWebSocket을 넘겨주게 되어 있고 이 값이 HttpEngine의 생성시 넘어오게 됩니다.
sendRequest 부터 시작해 봅니다. 이 함수에서 가장 먼저 하는 일은 헤더의 재생성입니다. 확인하는 헤더의 값은 Host, Connection, Accept-Encoding, Cookie, User-Agent입니다.
Host가 없으면 요청 url로부터 host 값을 찾은 후 이 값을 Host 헤더에 넣어줍니다.
if (request.header("Host") == null) {
  result.header("Host", hostHeader(request.url()));
}
public static String hostHeader(URL url) {
  // getEffectivePort 함수는 url에서 port를 찾고 getDefaultPort는 url의 프로토콜로부터 기본 포트(http는 80, https는 443)를 찾습니다.
  return getEffectivePort(url) != getDefaultPort(url.getProtocol())
      ? url.getHost() + ":" + url.getPort()
      : url.getHost();
}
Connection이 없고 connection의 프로토콜이 http 1.0이 아니면 Connection에 Keep-Alive를 넣어줍니다.
if ((connection == null || connection.getProtocol() != Protocol.HTTP_1_0)
    && request.header("Connection") == null) {
  result.header("Connection", "Keep-Alive");
}
Accep-Encoding이 없으면 OkHttp는 gzip을 기본으로 사용하므로 gzip을 설정해 줍니다.
if (request.header("Accept-Encoding") == null) {
  transparentGzip = true;
  result.header("Accept-Encoding", "gzip");
}
OkHttpClient의 cookie handler를 사용해서 url에 관련된 쿠키들을 찾습니다. 이렇게 찾은 값들을 Cookie와 Cookie2 헤더에 넣어줍니다. OkHttpClient에 별도로 지정하지 않았으면 기본 핸들러가 사용됩니다.
result.cookieHandler = CookieHandler.getDefault();

User-Agent가 없으면 OkHttp의 버전 정보를 넣어줍니다.
if (request.header("User-Agent") == null) {
  result.header("User-Agent", Version.userAgent());
}
다음으로는 내부 캐시를 확인합니다.
InternalCache responseCache = Internal.instance.internalCache(client);
특별한 작업을 해주지 않았으면 null이 될 것입니다. CacheStrategy.Factory를 통해 캐시된 Response가 있는지 찾습니다. 있으면 실제 connect가 필요없이 이 Response를 사용하면 될 것입니다. 캐시된 Response가 없으면 connect 함수를 통해 Connection을 만듭니다. connect 함수에서는 address를 생성하고 라우팅을 위한 정보를 찾아낸 후 이러한 정보들을 담고 있는 Connection을 생성해 줍니다. 이때 Connection은 ConnectionPool을 통해 관리가 됩니다.
Connection을 만들기 위해 제일 먼저 하는 일은 Address를 만드는 것입니다. Request로부터 url을 가져오고 나머지 Address 생성에 필요한 값들은 OkHttpClient로부터 가져옵니다.
private static Address createAddress(OkHttpClient client, Request request)
    throws RequestException {
  String uriHost = request.url().getHost();
  if (uriHost == null || uriHost.length() == 0) {
    throw new RequestException(new UnknownHostException(request.url().toString()));
  }

  SSLSocketFactory sslSocketFactory = null;
  HostnameVerifier hostnameVerifier = null;
  CertificatePinner certificatePinner = null;
  if (request.isHttps()) {
    sslSocketFactory = client.getSslSocketFactory();
    hostnameVerifier = client.getHostnameVerifier();
    certificatePinner = client.getCertificatePinner();
  }

  return new Address(uriHost, getEffectivePort(request.url()),
      client.getSocketFactory(), sslSocketFactory, hostnameVerifier, certificatePinner,
      client.getAuthenticator(), client.getProxy(), client.getProtocols(),
      client.getConnectionSpecs(), client.getProxySelector());
}
Address class는 connection에 관련된 정보들을 모아 놓고 있는 class입니다. 대부분 get함수로 이루어져 있습니다.
다음으로는 서버에 연결하기 위한 route를 설정합니다. RouterSelector.get 함수를 통해 RouteSelector를 생성할 수 있습니다.
public static RouteSelector get(Address address, Request request, OkHttpClient client)
    throws IOException {
  return new RouteSelector(address, request.uri(), client);
}

댓글 없음:

댓글 쓰기

Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...