1/*
2 *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11package org.appspot.apprtc.util;
12
13import java.io.IOException;
14import java.io.InputStream;
15import java.io.OutputStream;
16import java.net.HttpURLConnection;
17import java.net.SocketTimeoutException;
18import java.net.URL;
19import java.util.Scanner;
20
21/**
22 * Asynchronous http requests implementation.
23 */
24public class AsyncHttpURLConnection {
25  private static final int HTTP_TIMEOUT_MS = 8000;
26  private static final String HTTP_ORIGIN = "https://apprtc.appspot.com";
27  private final String method;
28  private final String url;
29  private final String message;
30  private final AsyncHttpEvents events;
31  private String contentType;
32
33  /**
34   * Http requests callbacks.
35   */
36  public interface AsyncHttpEvents {
37    public void onHttpError(String errorMessage);
38    public void onHttpComplete(String response);
39  }
40
41  public AsyncHttpURLConnection(String method, String url, String message,
42      AsyncHttpEvents events) {
43    this.method = method;
44    this.url = url;
45    this.message = message;
46    this.events = events;
47  }
48
49  public void setContentType(String contentType) {
50    this.contentType = contentType;
51  }
52
53  public void send() {
54    Runnable runHttp = new Runnable() {
55      public void run() {
56        sendHttpMessage();
57      }
58    };
59    new Thread(runHttp).start();
60  }
61
62  private void sendHttpMessage() {
63    try {
64      HttpURLConnection connection =
65        (HttpURLConnection) new URL(url).openConnection();
66      byte[] postData = new byte[0];
67      if (message != null) {
68        postData = message.getBytes("UTF-8");
69      }
70      connection.setRequestMethod(method);
71      connection.setUseCaches(false);
72      connection.setDoInput(true);
73      connection.setConnectTimeout(HTTP_TIMEOUT_MS);
74      connection.setReadTimeout(HTTP_TIMEOUT_MS);
75      // TODO(glaznev) - query request origin from pref_room_server_url_key preferences.
76      connection.addRequestProperty("origin", HTTP_ORIGIN);
77      boolean doOutput = false;
78      if (method.equals("POST")) {
79        doOutput = true;
80        connection.setDoOutput(true);
81        connection.setFixedLengthStreamingMode(postData.length);
82      }
83      if (contentType == null) {
84        connection.setRequestProperty("Content-Type", "text/plain; charset=utf-8");
85      } else {
86        connection.setRequestProperty("Content-Type", contentType);
87      }
88
89      // Send POST request.
90      if (doOutput && postData.length > 0) {
91        OutputStream outStream = connection.getOutputStream();
92        outStream.write(postData);
93        outStream.close();
94      }
95
96      // Get response.
97      int responseCode = connection.getResponseCode();
98      if (responseCode != 200) {
99        events.onHttpError("Non-200 response to " + method + " to URL: "
100            + url + " : " + connection.getHeaderField(null));
101        connection.disconnect();
102        return;
103      }
104      InputStream responseStream = connection.getInputStream();
105      String response = drainStream(responseStream);
106      responseStream.close();
107      connection.disconnect();
108      events.onHttpComplete(response);
109    } catch (SocketTimeoutException e) {
110      events.onHttpError("HTTP " + method + " to " + url + " timeout");
111    } catch (IOException e) {
112      events.onHttpError("HTTP " + method + " to " + url + " error: "
113          + e.getMessage());
114    }
115  }
116
117  // Return the contents of an InputStream as a String.
118  private static String drainStream(InputStream in) {
119    Scanner s = new Scanner(in).useDelimiter("\\A");
120    return s.hasNext() ? s.next() : "";
121  }
122}
123