File: http_request.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (157 lines) | stat: -rw-r--r-- 4,990 bytes parent folder | download | duplicates (9)
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
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
#define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_

#include <stddef.h>

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <string_view>

#include "base/strings/string_util.h"
#include "net/ssl/ssl_info.h"
#include "url/gurl.h"

namespace net {

class HttpChunkedDecoder;

namespace test_server {

// Methods of HTTP requests supported by the test HTTP server.
enum HttpMethod {
  METHOD_UNKNOWN,
  METHOD_GET,
  METHOD_HEAD,
  METHOD_POST,
  METHOD_PUT,
  METHOD_DELETE,
  METHOD_PATCH,
  METHOD_CONNECT,
  METHOD_OPTIONS,
};

// Represents a HTTP request. Since it can be big, `use std::unique_ptr` to pass
// it instead of copying. However, the struct is copyable so tests can save and
// examine a HTTP request.
struct HttpRequest {
  struct CaseInsensitiveStringComparator {
    // Allow using std::string_view instead of string for `find()`.
    using is_transparent = void;

    bool operator()(std::string_view left, std::string_view right) const {
      return base::CompareCaseInsensitiveASCII(left, right) < 0;
    }
  };

  using HeaderMap =
      std::map<std::string, std::string, CaseInsensitiveStringComparator>;

  HttpRequest();
  HttpRequest(const HttpRequest& other);
  ~HttpRequest();

  // Returns a GURL as a convenience to extract the path and query strings.
  GURL GetURL() const;

  // The request target. For most methods, this will start with '/', e.g.,
  // "/test?query=foo". If `method` is `METHOD_OPTIONS`, it may also be "*". If
  // `method` is `METHOD_CONNECT`, it will instead be a string like
  // "example.com:443".
  std::string relative_url;
  GURL base_url;
  // The HTTP method. If unknown, this will be `METHOD_UNKNOWN` and the actual
  // method will be in `method_string`.
  HttpMethod method = METHOD_UNKNOWN;
  std::string method_string;
  std::string all_headers;
  HeaderMap headers;
  std::string content;
  bool has_content = false;
  std::optional<SSLInfo> ssl_info;
};

// Parses the input data and produces a valid HttpRequest object. If there is
// more than one request in one chunk, then only the first one will be parsed.
// The common use is as below:
// HttpRequestParser parser;
// (...)
// void OnDataChunkReceived(Socket* socket, const char* data, int size) {
//   parser.ProcessChunk(std::string(data, size));
//   if (parser.ParseRequest() == HttpRequestParser::ACCEPTED) {
//     std::unique_ptr<HttpRequest> request = parser.GetRequest();
//     (... process the request ...)
//   }
class HttpRequestParser {
 public:
  // Parsing result.
  enum ParseResult {
    WAITING,  // A request is not completed yet, waiting for more data.
    ACCEPTED,  // A request has been parsed and it is ready to be processed.
  };

  // Parser state.
  enum State {
    STATE_HEADERS,  // Waiting for a request headers.
    STATE_CONTENT,  // Waiting for content data.
    STATE_ACCEPTED,  // Request has been parsed.
  };

  HttpRequestParser();

  HttpRequestParser(const HttpRequestParser&) = delete;
  HttpRequestParser& operator=(const HttpRequestParser&) = delete;

  ~HttpRequestParser();

  // Adds chunk of data into the internal buffer.
  void ProcessChunk(std::string_view data);

  // Parses the http request (including data - if provided).
  // If returns ACCEPTED, then it means that the whole request has been found
  // in the internal buffer (and parsed). After calling GetRequest(), it will be
  // ready to parse another request.
  ParseResult ParseRequest();

  // Retrieves parsed request. Can be only called, when the parser is in
  // STATE_ACCEPTED state. After calling it, the parser is ready to parse
  // another request.
  std::unique_ptr<HttpRequest> GetRequest();

  // Returns `METHOD_UNKNOWN` if `token` is not a recognized method. Methods are
  // case-sensitive.
  static HttpMethod GetMethodType(std::string_view token);

 private:
  // Parses headers and returns ACCEPTED if whole request was parsed. Otherwise
  // returns WAITING.
  ParseResult ParseHeaders();

  // Parses request's content data and returns ACCEPTED if all of it have been
  // processed. Chunked Transfer Encoding is supported.
  ParseResult ParseContent();

  // Fetches the next line from the buffer. Result does not contain \r\n.
  // Returns an empty string for an empty line. It will assert if there is
  // no line available.
  std::string ShiftLine();

  std::unique_ptr<HttpRequest> http_request_;
  std::string buffer_;
  size_t buffer_position_ = 0;  // Current position in the internal buffer.
  State state_ = STATE_HEADERS;
  // Content length of the request currently being parsed.
  size_t declared_content_length_ = 0;

  std::unique_ptr<HttpChunkedDecoder> chunked_decoder_;
};

}  // namespace test_server
}  // namespace net

#endif  // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_