WPILibC++  2020.3.2-60-g3011ebe
HttpUtil.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #ifndef WPIUTIL_WPI_HTTPUTIL_H_
9 #define WPIUTIL_WPI_HTTPUTIL_H_
10 
11 #include <memory>
12 #include <string>
13 #include <utility>
14 #include <vector>
15 
16 #include "wpi/ArrayRef.h"
17 #include "wpi/NetworkStream.h"
18 #include "wpi/SmallString.h"
19 #include "wpi/SmallVector.h"
20 #include "wpi/StringMap.h"
21 #include "wpi/StringRef.h"
22 #include "wpi/Twine.h"
23 #include "wpi/raw_istream.h"
24 #include "wpi/raw_socket_istream.h"
25 #include "wpi/raw_socket_ostream.h"
26 
27 namespace wpi {
28 
29 // Unescape a %xx-encoded URI.
30 // @param buf Buffer for output
31 // @param error Set to true if an error occurred
32 // @return Escaped string
33 StringRef UnescapeURI(const Twine& str, SmallVectorImpl<char>& buf,
34  bool* error);
35 
36 // Escape a string with %xx-encoding.
37 // @param buf Buffer for output
38 // @param spacePlus If true, encodes spaces to '+' rather than "%20"
39 // @return Escaped string
40 StringRef EscapeURI(const Twine& str, SmallVectorImpl<char>& buf,
41  bool spacePlus = true);
42 
43 // Parse a set of HTTP headers. Saves just the Content-Type and Content-Length
44 // fields.
45 // @param is Input stream
46 // @param contentType If not null, Content-Type contents are saved here.
47 // @param contentLength If not null, Content-Length contents are saved here.
48 // @return False if error occurred in input stream
49 bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
50  SmallVectorImpl<char>* contentLength);
51 
52 // Look for a MIME multi-part boundary. On return, the input stream will
53 // be located at the character following the boundary (usually "\r\n").
54 // @param is Input stream
55 // @param boundary Boundary string to scan for (not including "--" prefix)
56 // @param saveBuf If not null, all scanned characters up to but not including
57 // the boundary are saved to this string
58 // @return False if error occurred on input stream, true if boundary found.
59 bool FindMultipartBoundary(wpi::raw_istream& is, StringRef boundary,
60  std::string* saveBuf);
61 
62 class HttpLocation {
63  public:
64  HttpLocation() = default;
65  HttpLocation(const Twine& url_, bool* error, std::string* errorMsg);
66 
67  std::string url; // retain copy
68  std::string user; // unescaped
69  std::string password; // unescaped
70  std::string host;
71  int port;
72  std::string path; // escaped, not including leading '/'
73  std::vector<std::pair<std::string, std::string>> params; // unescaped
74  std::string fragment;
75 };
76 
77 class HttpRequest {
78  public:
79  HttpRequest() = default;
80 
81  explicit HttpRequest(const HttpLocation& loc)
82  : host{loc.host}, port{loc.port} {
83  SetPath(loc.path, loc.params);
84  SetAuth(loc);
85  }
86 
87  template <typename T>
88  HttpRequest(const HttpLocation& loc, const T& extraParams);
89 
90  HttpRequest(const HttpLocation& loc, StringRef path_)
91  : host{loc.host}, port{loc.port}, path{path_} {
92  SetAuth(loc);
93  }
94 
95  template <typename T>
96  HttpRequest(const HttpLocation& loc, StringRef path_, const T& params)
97  : host{loc.host}, port{loc.port} {
98  SetPath(path_, params);
99  SetAuth(loc);
100  }
101 
102  SmallString<128> host;
103  int port;
104  std::string auth;
105  SmallString<128> path;
106 
107  private:
108  void SetAuth(const HttpLocation& loc);
109  template <typename T>
110  void SetPath(StringRef path_, const T& params);
111 
112  template <typename T>
113  static StringRef GetFirst(const T& elem) {
114  return elem.first;
115  }
116  template <typename T>
117  static StringRef GetFirst(const StringMapEntry<T>& elem) {
118  return elem.getKey();
119  }
120  template <typename T>
121  static StringRef GetSecond(const T& elem) {
122  return elem.second;
123  }
124 };
125 
127  public:
128  HttpConnection(std::unique_ptr<wpi::NetworkStream> stream_, int timeout)
129  : stream{std::move(stream_)}, is{*stream, timeout}, os{*stream, true} {}
130 
131  bool Handshake(const HttpRequest& request, std::string* warnMsg);
132 
133  std::unique_ptr<wpi::NetworkStream> stream;
136 
137  // Valid after Handshake() is successful
138  SmallString<64> contentType;
139  SmallString<64> contentLength;
140 
141  explicit operator bool() const { return stream && !is.has_error(); }
142 };
143 
145  public:
146  explicit HttpMultipartScanner(StringRef boundary, bool saveSkipped = false) {
147  Reset(saveSkipped);
148  SetBoundary(boundary);
149  }
150 
151  // Change the boundary. This is only safe to do when IsDone() is true (or
152  // immediately after construction).
153  void SetBoundary(StringRef boundary);
154 
155  // Reset the scanner. This allows reuse of internal buffers.
156  void Reset(bool saveSkipped = false);
157 
158  // Execute the scanner. Will automatically call Reset() on entry if IsDone()
159  // is true.
160  // @param in input data
161  // @return the input not consumed; empty if all input consumed
162  StringRef Execute(StringRef in);
163 
164  // Returns true when the boundary has been found.
165  bool IsDone() const { return m_state == kDone; }
166 
167  // Get the skipped data. Will be empty if saveSkipped was false.
168  StringRef GetSkipped() const {
169  return m_saveSkipped ? StringRef{m_buf} : StringRef{};
170  }
171 
172  private:
173  SmallString<64> m_boundaryWith, m_boundaryWithout;
174 
175  // Internal state
176  enum State { kBoundary, kPadding, kDone };
177  State m_state;
178  size_t m_posWith, m_posWithout;
179  enum Dashes { kUnknown, kWith, kWithout };
180  Dashes m_dashes;
181 
182  // Buffer
183  bool m_saveSkipped;
184  std::string m_buf;
185 };
186 
187 } // namespace wpi
188 
189 #include "HttpUtil.inl"
190 
191 #endif // WPIUTIL_WPI_HTTPUTIL_H_
wpi::HttpRequest
Definition: HttpUtil.h:77
wpi::HttpLocation
Definition: HttpUtil.h:62
wpi::raw_socket_ostream
Definition: raw_socket_ostream.h:17
wpi::raw_istream
Definition: raw_istream.h:26
wpi
WPILib C++ utilities (wpiutil) namespace.
Definition: Endian.h:31
wpi::SmallString< 128 >
wpi::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
wpi::HttpMultipartScanner
Definition: HttpUtil.h:144
wpi::HttpConnection
Definition: HttpUtil.h:126
wpi::StringMapEntry
StringMapEntry - This is used to represent one value that is inserted into a StringMap.
Definition: StringMap.h:39
wpi::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:85
wpi::raw_socket_istream
Definition: raw_socket_istream.h:17