Home | History | Annotate | Download | only in okhttp
      1 /*
      2  * Copyright (C) 2013 Square, Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.squareup.okhttp;
     17 
     18 import com.squareup.okhttp.internal.http.HttpMethod;
     19 import java.io.IOException;
     20 import java.net.URI;
     21 import java.net.URL;
     22 import java.util.List;
     23 
     24 /**
     25  * An HTTP request. Instances of this class are immutable if their {@link #body}
     26  * is null or itself immutable.
     27  */
     28 public final class Request {
     29   private final HttpUrl url;
     30   private final String method;
     31   private final Headers headers;
     32   private final RequestBody body;
     33   private final Object tag;
     34 
     35   private volatile URL javaNetUrl; // Lazily initialized.
     36   private volatile URI javaNetUri; // Lazily initialized.
     37   private volatile CacheControl cacheControl; // Lazily initialized.
     38 
     39   private Request(Builder builder) {
     40     this.url = builder.url;
     41     this.method = builder.method;
     42     this.headers = builder.headers.build();
     43     this.body = builder.body;
     44     this.tag = builder.tag != null ? builder.tag : this;
     45   }
     46 
     47   public HttpUrl httpUrl() {
     48     return url;
     49   }
     50 
     51   public URL url() {
     52     URL result = javaNetUrl;
     53     return result != null ? result : (javaNetUrl = url.url());
     54   }
     55 
     56   public URI uri() throws IOException {
     57     try {
     58       URI result = javaNetUri;
     59       return result != null ? result : (javaNetUri = url.uri());
     60     } catch (IllegalStateException e) {
     61       throw new IOException(e.getMessage());
     62     }
     63   }
     64 
     65   public String urlString() {
     66     return url.toString();
     67   }
     68 
     69   public String method() {
     70     return method;
     71   }
     72 
     73   public Headers headers() {
     74     return headers;
     75   }
     76 
     77   public String header(String name) {
     78     return headers.get(name);
     79   }
     80 
     81   public List<String> headers(String name) {
     82     return headers.values(name);
     83   }
     84 
     85   public RequestBody body() {
     86     return body;
     87   }
     88 
     89   public Object tag() {
     90     return tag;
     91   }
     92 
     93   public Builder newBuilder() {
     94     return new Builder(this);
     95   }
     96 
     97   /**
     98    * Returns the cache control directives for this response. This is never null,
     99    * even if this response contains no {@code Cache-Control} header.
    100    */
    101   public CacheControl cacheControl() {
    102     CacheControl result = cacheControl;
    103     return result != null ? result : (cacheControl = CacheControl.parse(headers));
    104   }
    105 
    106   public boolean isHttps() {
    107     return url.isHttps();
    108   }
    109 
    110   @Override public String toString() {
    111     return "Request{method="
    112         + method
    113         + ", url="
    114         + url
    115         + ", tag="
    116         + (tag != this ? tag : null)
    117         + '}';
    118   }
    119 
    120   public static class Builder {
    121     private HttpUrl url;
    122     private String method;
    123     private Headers.Builder headers;
    124     private RequestBody body;
    125     private Object tag;
    126 
    127     public Builder() {
    128       this.method = "GET";
    129       this.headers = new Headers.Builder();
    130     }
    131 
    132     private Builder(Request request) {
    133       this.url = request.url;
    134       this.method = request.method;
    135       this.body = request.body;
    136       this.tag = request.tag;
    137       this.headers = request.headers.newBuilder();
    138     }
    139 
    140     public Builder url(HttpUrl url) {
    141       if (url == null) throw new IllegalArgumentException("url == null");
    142       this.url = url;
    143       return this;
    144     }
    145 
    146     /**
    147      * Sets the URL target of this request.
    148      *
    149      * @throws IllegalArgumentException if {@code url} is not a valid HTTP or HTTPS URL. Avoid this
    150      *     exception by calling {@link HttpUrl#parse}; it returns null for invalid URLs.
    151      */
    152     public Builder url(String url) {
    153       if (url == null) throw new IllegalArgumentException("url == null");
    154 
    155       // Silently replace websocket URLs with HTTP URLs.
    156       if (url.regionMatches(true, 0, "ws:", 0, 3)) {
    157         url = "http:" + url.substring(3);
    158       } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
    159         url = "https:" + url.substring(4);
    160       }
    161 
    162       HttpUrl parsed = HttpUrl.parse(url);
    163       if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
    164       return url(parsed);
    165     }
    166 
    167     /**
    168      * Sets the URL target of this request.
    169      *
    170      * @throws IllegalArgumentException if the scheme of {@code url} is not {@code http} or {@code
    171      *     https}.
    172      */
    173     public Builder url(URL url) {
    174       if (url == null) throw new IllegalArgumentException("url == null");
    175       HttpUrl parsed = HttpUrl.get(url);
    176       if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
    177       return url(parsed);
    178     }
    179 
    180     /**
    181      * Sets the header named {@code name} to {@code value}. If this request
    182      * already has any headers with that name, they are all replaced.
    183      */
    184     public Builder header(String name, String value) {
    185       headers.set(name, value);
    186       return this;
    187     }
    188 
    189     /**
    190      * Adds a header with {@code name} and {@code value}. Prefer this method for
    191      * multiply-valued headers like "Cookie".
    192      *
    193      * <p>Note that for some headers including {@code Content-Length} and {@code Content-Encoding},
    194      * OkHttp may replace {@code value} with a header derived from the request body.
    195      */
    196     public Builder addHeader(String name, String value) {
    197       headers.add(name, value);
    198       return this;
    199     }
    200 
    201     public Builder removeHeader(String name) {
    202       headers.removeAll(name);
    203       return this;
    204     }
    205 
    206     /** Removes all headers on this builder and adds {@code headers}. */
    207     public Builder headers(Headers headers) {
    208       this.headers = headers.newBuilder();
    209       return this;
    210     }
    211 
    212     /**
    213      * Sets this request's {@code Cache-Control} header, replacing any cache
    214      * control headers already present. If {@code cacheControl} doesn't define
    215      * any directives, this clears this request's cache-control headers.
    216      */
    217     public Builder cacheControl(CacheControl cacheControl) {
    218       String value = cacheControl.toString();
    219       if (value.isEmpty()) return removeHeader("Cache-Control");
    220       return header("Cache-Control", value);
    221     }
    222 
    223     public Builder get() {
    224       return method("GET", null);
    225     }
    226 
    227     public Builder head() {
    228       return method("HEAD", null);
    229     }
    230 
    231     public Builder post(RequestBody body) {
    232       return method("POST", body);
    233     }
    234 
    235     public Builder delete(RequestBody body) {
    236       return method("DELETE", body);
    237     }
    238 
    239     public Builder delete() {
    240       return delete(RequestBody.create(null, new byte[0]));
    241     }
    242 
    243     public Builder put(RequestBody body) {
    244       return method("PUT", body);
    245     }
    246 
    247     public Builder patch(RequestBody body) {
    248       return method("PATCH", body);
    249     }
    250 
    251     public Builder method(String method, RequestBody body) {
    252       if (method == null || method.length() == 0) {
    253         throw new IllegalArgumentException("method == null || method.length() == 0");
    254       }
    255       if (body != null && !HttpMethod.permitsRequestBody(method)) {
    256         throw new IllegalArgumentException("method " + method + " must not have a request body.");
    257       }
    258       if (body == null && HttpMethod.requiresRequestBody(method)) {
    259         throw new IllegalArgumentException("method " + method + " must have a request body.");
    260       }
    261       this.method = method;
    262       this.body = body;
    263       return this;
    264     }
    265 
    266     /**
    267      * Attaches {@code tag} to the request. It can be used later to cancel the
    268      * request. If the tag is unspecified or null, the request is canceled by
    269      * using the request itself as the tag.
    270      */
    271     public Builder tag(Object tag) {
    272       this.tag = tag;
    273       return this;
    274     }
    275 
    276     public Request build() {
    277       if (url == null) throw new IllegalStateException("url == null");
    278       return new Request(this);
    279     }
    280   }
    281 }
    282