summaryrefslogtreecommitdiffstats
path: root/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/SyncResponse.java
blob: 177d7aabad9b3d761062d8703c9d2d527d1d5e55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.gecko.sync.net;

import android.support.annotation.Nullable;

import org.mozilla.gecko.sync.Utils;

import ch.boye.httpclientandroidlib.HttpResponse;

public class SyncResponse extends MozResponse {
  public static final String X_WEAVE_BACKOFF = "x-weave-backoff";
  public static final String X_BACKOFF = "x-backoff";
  public static final String X_LAST_MODIFIED = "x-last-modified";
  public static final String X_WEAVE_TIMESTAMP = "x-weave-timestamp";
  public static final String X_WEAVE_RECORDS = "x-weave-records";
  public static final String X_WEAVE_QUOTA_REMAINING = "x-weave-quota-remaining";
  public static final String X_WEAVE_ALERT = "x-weave-alert";
  public static final String X_WEAVE_NEXT_OFFSET = "x-weave-next-offset";

  public SyncResponse(HttpResponse res) {
    super(res);
  }

  /**
   * @return A number of seconds, or -1 if the 'X-Weave-Backoff' header was not
   *         present.
   */
  public int weaveBackoffInSeconds() throws NumberFormatException {
    return this.getIntegerHeader(X_WEAVE_BACKOFF);
  }

  /**
   * @return A number of seconds, or -1 if the 'X-Backoff' header was not
   *         present.
   */
  public int xBackoffInSeconds() throws NumberFormatException {
    return this.getIntegerHeader(X_BACKOFF);
  }

  /**
   * Extract a number of seconds, or -1 if none of the specified headers were present.
   *
   * @param includeRetryAfter
   *          if <code>true</code>, the Retry-After header is excluded. This is
   *          useful for processing non-error responses where a Retry-After
   *          header would be unexpected.
   * @return the maximum of the three possible backoff headers, in seconds.
   */
  public int totalBackoffInSeconds(boolean includeRetryAfter) {
    int retryAfterInSeconds = -1;
    if (includeRetryAfter) {
      try {
        retryAfterInSeconds = retryAfterInSeconds();
      } catch (NumberFormatException e) {
      }
    }

    int weaveBackoffInSeconds = -1;
    try {
      weaveBackoffInSeconds = weaveBackoffInSeconds();
    } catch (NumberFormatException e) {
    }

    int backoffInSeconds = -1;
    try {
      backoffInSeconds = xBackoffInSeconds();
    } catch (NumberFormatException e) {
    }

    int totalBackoff = Math.max(retryAfterInSeconds, Math.max(backoffInSeconds, weaveBackoffInSeconds));
    if (totalBackoff < 0) {
      return -1;
    } else {
      return totalBackoff;
    }
  }

  /**
   * @return A number of milliseconds, or -1 if neither the 'Retry-After',
   *         'X-Backoff', or 'X-Weave-Backoff' header were present.
   */
  public long totalBackoffInMilliseconds() {
    long totalBackoff = totalBackoffInSeconds(true);
    if (totalBackoff < 0) {
      return -1;
    } else {
      return 1000 * totalBackoff;
    }
  }

  public long normalizedWeaveTimestamp() {
    return normalizedTimestampForHeader(X_WEAVE_TIMESTAMP);
  }

  /**
   * Timestamps returned from a Sync server are decimal numbers of seconds,
   * e.g., 1323393518.04.
   *
   * We want milliseconds since epoch.
   *
   * @return milliseconds since the epoch, as a long, or -1 if the header
   *         was missing or invalid.
   */
  public long normalizedTimestampForHeader(String header) {
    if (!this.hasHeader(header)) {
      return -1;
    }

    return Utils.decimalSecondsToMilliseconds(
            this.response.getFirstHeader(header).getValue()
    );
  }

  public int weaveRecords() throws NumberFormatException {
    return this.getIntegerHeader(X_WEAVE_RECORDS);
  }

  public int weaveQuotaRemaining() throws NumberFormatException {
    return this.getIntegerHeader(X_WEAVE_QUOTA_REMAINING);
  }

  public String weaveAlert() {
    return this.getNonMissingHeader(X_WEAVE_ALERT);
  }

  /**
   * This header may be sent back with multi-record responses where the request included a limit parameter.
   * Its presence indicates that the number of available records exceeded the given limit.
   * The value from this header can be passed back in the offset parameter to retrieve additional records.
   * The value of this header will always be a string of characters from the urlsafe-base64 alphabet.
   * The specific contents of the string are an implementation detail of the server,
   * so clients should treat it as an opaque token.
   *
   * @return the offset header
   */
  public String weaveOffset() {
    return this.getNonMissingHeader(X_WEAVE_NEXT_OFFSET);
  }

  /**
   * This header gives the last-modified time of the target resource as seen during processing of the request,
   * and will be included in all success responses (200, 201, 204).
   * When given in response to a write request, this will be equal to the server’s current time and
   * to the new last-modified time of any BSOs created or changed by the request.
   * It is similar to the standard HTTP Last-Modified header,
   * but the value is a decimal timestamp rather than a HTTP-format date.
   *
   * @return the last modified header
   */
  @Nullable
  public String lastModified() {
    return this.getNonMissingHeader(X_LAST_MODIFIED);
  }
}