Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ios / web / net / request_group_util.mm
blob5aecb1047b6777978e5fb4ca36288c33ee03a456
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ios/web/net/request_group_util.h"
7 #include <Foundation/Foundation.h>
9 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "base/rand_util.h"
12 #include "base/strings/sys_string_conversions.h"
13 #import "net/base/mac/url_conversions.h"
14 #include "url/gurl.h"
16 namespace {
17 // Minimum length for a request group ID. A shorter string is considered as an
18 // invalid ID.
19 const int kMinimumIDLength = 5;
22 namespace web {
24 // Generates a request-group ID used to correlate web requests with the embedder
25 // that triggered it. It is important that the return value should not be unique
26 // for different users. See crbug/355613 for context.
27 NSString* GenerateNewRequestGroupID() {
28   const unsigned int kGroupSize = 1000;
29   static unsigned long count = 0;
30   static unsigned int offset = base::RandInt(0, kGroupSize - 1);
32   unsigned long current = count++;
33   if (current < kGroupSize)
34     current = (current + offset) % kGroupSize;
36   // The returned string must have a minimum of kMinimumIDLength characters, and
37   // no spaces.
38   // TODO(blundell): Develop a long-term solution to this problem.
39   // crbug.com/329243
40   return [NSString stringWithFormat:@"%06lu", current];
43 NSString* ExtractRequestGroupIDFromUserAgent(NSString* user_agent) {
44   if (![user_agent length])
45     return nil;
47   // The request_group_id is wrapped by parenthesis in the last space-delimited
48   // fragment.
49   NSString* fragment =
50       [[user_agent componentsSeparatedByString:@" "] lastObject];
51   NSString* request_group_id =
52       [fragment hasPrefix:@"("] && [fragment hasSuffix:@")"]
53           ? [fragment substringWithRange:NSMakeRange(1, [fragment length] - 2)]
54           : nil;
55   // GTLService constructs user agents that end with "(gzip)". To avoid these
56   // getting treated as having the request_group_id "gzip", short-circuit out if
57   // the request_group_id is not long enough to be a valid request_group_id (all
58   // valid request_group_id are at least kMinimumIDLength characters long).
59   // TODO(blundell): Develop a long-term solution to this problem.
60   // crbug.com/329243
61   if ([request_group_id length] < kMinimumIDLength)
62     return nil;
63   return request_group_id;
66 NSString* AddRequestGroupIDToUserAgent(NSString* base_user_agent,
67                                        NSString* request_group_id) {
68   if (!request_group_id)
69     return base_user_agent;
70   // TODO(blundell): Develop a long-term solution to this problem.
71   // crbug.com/329243
72   DCHECK([request_group_id length] >= kMinimumIDLength);
73   return
74       [NSString stringWithFormat:@"%@ (%@)", base_user_agent, request_group_id];
77 NSString* ExtractRequestGroupIDFromURL(NSURL* url) {
78   GURL gurl = net::GURLWithNSURL(url);
79   if (!gurl.has_username())
80     return nil;
82   std::string request_group_id_as_string;
83   if (base::Base64Decode(gurl.username(), &request_group_id_as_string))
84     return base::SysUTF8ToNSString(request_group_id_as_string);
86   return nil;
89 NSURL* AddRequestGroupIDToURL(NSURL* base_url, NSString* request_group_id) {
90   GURL url = net::GURLWithNSURL(base_url);
91   std::string base64RequestGroupID;
92   base::Base64Encode(base::SysNSStringToUTF8(request_group_id),
93                      &base64RequestGroupID);
94   GURL::Replacements replacements;
95   replacements.SetUsernameStr(base64RequestGroupID);
96   url = url.ReplaceComponents(replacements);
97   return net::NSURLWithGURL(url);
100 NSString* ExtractRequestGroupIDFromRequest(NSURLRequest* request,
101                                            NSString* application_scheme) {
102   NSString* user_agent =
103       [[request allHTTPHeaderFields] objectForKey:@"User-Agent"];
104   NSString* request_group_id = ExtractRequestGroupIDFromUserAgent(user_agent);
105   if (request_group_id)
106     return request_group_id;
107   if (application_scheme &&
108       [[request.mainDocumentURL scheme]
109           caseInsensitiveCompare:application_scheme] == NSOrderedSame) {
110     return ExtractRequestGroupIDFromURL(request.mainDocumentURL);
111   }
112   return nil;
115 }  // namespace web