Apache Mesos
http.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License
12 
13 #ifndef __PROCESS_HTTP_HPP__
14 #define __PROCESS_HTTP_HPP__
15 
16 #include <ctype.h>
17 #include <stdint.h>
18 
19 #include <atomic>
20 #include <initializer_list>
21 #include <iosfwd>
22 #include <memory>
23 #include <queue>
24 #include <string>
25 #include <vector>
26 
27 #include <boost/functional/hash.hpp>
28 
29 #include <process/address.hpp>
30 #include <process/clock.hpp>
31 #include <process/future.hpp>
32 #include <process/owned.hpp>
33 #include <process/pid.hpp>
34 #include <process/socket.hpp>
35 
36 #include <stout/error.hpp>
37 #include <stout/hashmap.hpp>
38 #include <stout/ip.hpp>
39 #include <stout/json.hpp>
40 #include <stout/jsonify.hpp>
41 #include <stout/none.hpp>
42 #include <stout/nothing.hpp>
43 #include <stout/option.hpp>
44 #include <stout/stringify.hpp>
45 #include <stout/strings.hpp>
46 #include <stout/try.hpp>
47 
48 namespace process {
49 
50 // Forward declaration to break cyclic dependency.
51 template <typename T>
52 class Future;
53 
54 namespace http {
55 
56 enum class Scheme {
57  HTTP,
58  HTTP_UNIX,
59 #ifdef USE_SSL_SOCKET
60  HTTPS,
61 #endif
62 };
63 
64 
65 namespace authentication {
66 
67 class Authenticator;
68 
69 struct Principal;
70 
79  const std::string& realm,
80  Owned<Authenticator> authenticator);
81 
82 
89 Future<Nothing> unsetAuthenticator(const std::string& realm);
90 
91 } // namespace authentication {
92 
93 // Forward declaration.
94 struct Request;
95 
96 namespace authorization {
97 
98 // The `AuthorizationCallbacks` type is used for a set of authorization
99 // callbacks used by libprocess to authorize HTTP endpoints. The key of the map
100 // contains the endpoint's path, while the value contains the callback.
101 typedef hashmap<std::string,
102  lambda::function<process::Future<bool>(
103  const Request,
106 
107 
108 // Set authorization callbacks for HTTP endpoints. These can be used to call out
109 // to an external, application-level authorizer. The callbacks should accept an
110 // HTTP request and an optional principal, and they should return a
111 // `Future<bool>` representing whether or not authorization was successful.
113 
114 
115 // Remove any authorization callbacks which were previously installed in
116 // libprocess.
117 void unsetCallbacks();
118 
119 } // namespace authorization {
120 
121 // Checks if the given status code is defined by RFC 2616.
122 bool isValidStatus(uint16_t code);
123 
124 // Represents a Uniform Resource Locator:
125 // scheme://domain|ip:port/path?query#fragment
126 //
127 // This is actually a URI-reference (see 4.1 of RFC 3986).
128 //
129 // TODO(bmahler): The default port should depend on the scheme!
130 struct URL
131 {
132  URL() = default;
133 
134  URL(const std::string& _scheme,
135  const std::string& _domain,
136  const std::string& _path,
137  const hashmap<std::string, std::string>& _query =
139  const Option<std::string>& _fragment = None())
140  : scheme(_scheme),
141  domain(_domain),
142  path(_path),
143  query(_query),
144  fragment(_fragment) {}
145 
146  URL(const std::string& _scheme,
147  const std::string& _domain,
148  const uint16_t _port = 80,
149  const std::string& _path = "/",
150  const hashmap<std::string, std::string>& _query =
152  const Option<std::string>& _fragment = None())
153  : scheme(_scheme),
154  domain(_domain),
155  port(_port),
156  path(_path),
157  query(_query),
158  fragment(_fragment) {}
159 
160  URL(const std::string& _scheme,
161  const net::IP& _ip,
162  const uint16_t _port = 80,
163  const std::string& _path = "/",
164  const hashmap<std::string, std::string>& _query =
166  const Option<std::string>& _fragment = None())
167  : scheme(_scheme),
168  ip(_ip),
169  port(_port),
170  path(_path),
171  query(_query),
172  fragment(_fragment) {}
173 
174  static Try<URL> parse(const std::string& urlString);
175 
180  bool isAbsolute() const;
181 
183 
184  // TODO(benh): Consider using unrestricted union for 'domain' and 'ip'.
188  std::string path;
191 };
192 
193 
194 std::ostream& operator<<(std::ostream& stream, const URL& url);
195 
196 
198 {
199  size_t operator()(const std::string& key) const
200  {
201  size_t seed = 0;
202  foreach (char c, key) {
203  boost::hash_combine(seed, ::tolower(c));
204  }
205  return seed;
206  }
207 };
208 
209 
211 {
212  bool operator()(const std::string& left, const std::string& right) const
213  {
214  if (left.size() != right.size()) {
215  return false;
216  }
217  for (size_t i = 0; i < left.size(); ++i) {
218  if (::tolower(left[i]) != ::tolower(right[i])) {
219  return false;
220  }
221  }
222  return true;
223  }
224 };
225 
226 
227 struct Status
228 {
229  static const uint16_t CONTINUE;
230  static const uint16_t SWITCHING_PROTOCOLS;
231  static const uint16_t OK;
232  static const uint16_t CREATED;
233  static const uint16_t ACCEPTED;
234  static const uint16_t NON_AUTHORITATIVE_INFORMATION;
235  static const uint16_t NO_CONTENT;
236  static const uint16_t RESET_CONTENT;
237  static const uint16_t PARTIAL_CONTENT;
238  static const uint16_t MULTIPLE_CHOICES;
239  static const uint16_t MOVED_PERMANENTLY;
240  static const uint16_t FOUND;
241  static const uint16_t SEE_OTHER;
242  static const uint16_t NOT_MODIFIED;
243  static const uint16_t USE_PROXY;
244  static const uint16_t TEMPORARY_REDIRECT;
245  static const uint16_t BAD_REQUEST;
246  static const uint16_t UNAUTHORIZED;
247  static const uint16_t PAYMENT_REQUIRED;
248  static const uint16_t FORBIDDEN;
249  static const uint16_t NOT_FOUND;
250  static const uint16_t METHOD_NOT_ALLOWED;
251  static const uint16_t NOT_ACCEPTABLE;
252  static const uint16_t PROXY_AUTHENTICATION_REQUIRED;
253  static const uint16_t REQUEST_TIMEOUT;
254  static const uint16_t CONFLICT;
255  static const uint16_t GONE;
256  static const uint16_t LENGTH_REQUIRED;
257  static const uint16_t PRECONDITION_FAILED;
258  static const uint16_t REQUEST_ENTITY_TOO_LARGE;
259  static const uint16_t REQUEST_URI_TOO_LARGE;
260  static const uint16_t UNSUPPORTED_MEDIA_TYPE;
261  static const uint16_t REQUESTED_RANGE_NOT_SATISFIABLE;
262  static const uint16_t EXPECTATION_FAILED;
263  static const uint16_t INTERNAL_SERVER_ERROR;
264  static const uint16_t NOT_IMPLEMENTED;
265  static const uint16_t BAD_GATEWAY;
266  static const uint16_t SERVICE_UNAVAILABLE;
267  static const uint16_t GATEWAY_TIMEOUT;
268  static const uint16_t HTTP_VERSION_NOT_SUPPORTED;
269 
270  static std::string string(uint16_t code);
271 };
272 
273 
274 // Represents an asynchronous in-memory unbuffered Pipe, currently
275 // used for streaming HTTP responses via chunked encoding. Note that
276 // being an in-memory pipe means that this cannot be used across OS
277 // processes.
278 //
279 // Much like unix pipes, data is read until end-of-file is
280 // encountered; this occurs when the write-end of the pipe is
281 // closed and there is no outstanding data left to read.
282 //
283 // Unlike unix pipes, if the read-end of the pipe is closed before
284 // the write-end is closed, rather than receiving SIGPIPE or EPIPE
285 // during a write, the writer is notified via a future. This future
286 // is discarded if the write-end is closed first.
287 //
288 // No buffering means that each non-empty write to the pipe will
289 // correspond to to an equivalent read from the pipe, and the
290 // reader must "keep up" with the writer in order to avoid
291 // unbounded memory growth.
292 //
293 // The writer can induce a failure on the reader in order to signal
294 // that an error has occurred. For example, if we are receiving a
295 // response but a disconnection occurs before the response is
296 // completed, we want the reader to detect that a disconnection
297 // occurred!
298 //
299 // TODO(bmahler): Consider aggregating writes into larger reads to
300 // help the reader keep up (a process::Stream abstraction with
301 // backpressure would obviate the need for this).
302 //
303 // TODO(bmahler): Add a more general process::Stream<T> abstraction
304 // to represent asynchronous finite/infinite streams (possibly
305 // with "backpressure" on the writer). This is broadly useful
306 // (e.g. allocator can expose Stream<Allocation>, http::Pipe
307 // becomes Stream<string>, process::Queue<T> is just an infinite
308 // Stream<T> (i.e. completion and error semantics hidden)).
309 class Pipe
310 {
311 private:
312  struct Data; // Forward declaration.
313 
314 public:
315  class Reader
316  {
317  public:
318  // Returns data written to the pipe.
319  // Returns an empty read when end-of-file is reached.
320  // Returns Failure if the writer failed, or the read-end
321  // is closed.
323 
324  // Performs a series of asynchronous reads, until EOF is reached.
325  // Returns the concatenated result of the reads.
326  // Returns Failure if the writer failed, or the read-end
327  // is closed.
328  Future<std::string> readAll();
329 
330  // Closing the read-end of the pipe before the write-end closes
331  // or fails will notify the writer that the reader is no longer
332  // interested. Returns false if the read-end was already closed.
333  bool close();
334 
335  // Comparison operators useful for checking connection equality.
336  bool operator==(const Reader& other) const { return data == other.data; }
337  bool operator!=(const Reader& other) const { return !(*this == other); }
338 
339  private:
340  friend class Pipe;
341 
342  enum State
343  {
344  OPEN,
345  CLOSED,
346  };
347 
348  explicit Reader(const std::shared_ptr<Data>& _data)
349  : data(_data) {}
350 
351  std::shared_ptr<Data> data;
352  };
353 
354  class Writer
355  {
356  public:
357  // Returns false if the data could not be written because
358  // either end of the pipe was already closed. Note that an
359  // empty write has no effect.
360  bool write(std::string s);
361 
362  // Closing the write-end of the pipe will send end-of-file
363  // to the reader. Returns false if the write-end of the pipe
364  // was already closed or failed.
365  bool close();
366 
367  // Closes the write-end of the pipe but sends a failure
368  // to the reader rather than end-of-file. Returns false
369  // if the write-end of the pipe was already closed or failed.
370  bool fail(const std::string& message);
371 
372  // Returns Nothing when the read-end of the pipe is closed
373  // before the write-end is closed, which means the reader
374  // was unable to continue reading!
375  Future<Nothing> readerClosed() const;
376 
377  // Comparison operators useful for checking connection equality.
378  bool operator==(const Writer& other) const { return data == other.data; }
379  bool operator!=(const Writer& other) const { return !(*this == other); }
380  private:
381  friend class Pipe;
382 
383  enum State
384  {
385  OPEN,
386  CLOSED,
387  FAILED,
388  };
389 
390  explicit Writer(const std::shared_ptr<Data>& _data)
391  : data(_data) {}
392 
393  std::shared_ptr<Data> data;
394  };
395 
397  : data(new Data()) {}
398 
399  Reader reader() const;
400  Writer writer() const;
401 
402  // Comparison operators useful for checking connection equality.
403  bool operator==(const Pipe& other) const { return data == other.data; }
404  bool operator!=(const Pipe& other) const { return !(*this == other); }
405 private:
406  struct Data
407  {
408  Data()
409  : readEnd(Reader::OPEN), writeEnd(Writer::OPEN) {}
410 
411  // Rather than use a process to serialize access to the pipe's
412  // internal data we use a 'std::atomic_flag'.
413  std::atomic_flag lock = ATOMIC_FLAG_INIT;
414 
415  Reader::State readEnd;
416  Writer::State writeEnd;
417 
418  // Represents readers waiting for data from the pipe.
419  std::queue<Owned<Promise<std::string>>> reads;
420 
421  // Represents unread writes in the pipe. Note that we omit
422  // empty strings as they serve as a signal for end-of-file.
423  std::queue<std::string> writes;
424 
425  // Signals when the read-end is closed before the write-end.
426  Promise<Nothing> readerClosure;
427 
428  // Failure reason when the 'writeEnd' is FAILED.
429  Option<Failure> failure;
430  };
431 
432  std::shared_ptr<Data> data;
433 };
434 
435 
436 namespace header {
437 
438 // https://tools.ietf.org/html/rfc2617.
440 {
441 public:
442  static constexpr const char* NAME = "WWW-Authenticate";
443 
445  const std::string& authScheme,
446  const hashmap<std::string, std::string>& authParam)
447  : authScheme_(authScheme),
448  authParam_(authParam) {}
449 
450  static Try<WWWAuthenticate> create(const std::string& input);
451 
452  std::string authScheme();
454 
455 private:
456  // According to RFC, HTTP/1.1 server may return multiple challenges
457  // with a 401 (Authenticate) response. Each challenage is in the
458  // format of 'auth-scheme 1*SP 1#auth-param' and each challenage may
459  // use a different auth-scheme.
460  // https://tools.ietf.org/html/rfc2617#section-4.6
461  //
462  // TODO(gilbert): We assume there is only one authenticate challenge.
463  // Multiple challenges should be supported as well.
464  std::string authScheme_;
466 };
467 
468 } // namespace header {
469 
470 
471 class Headers : public hashmap<
472  std::string,
473  std::string,
474  CaseInsensitiveHash,
475  CaseInsensitiveEqual>
476 {
477 public:
478  Headers() {}
479 
480  Headers(const std::map<std::string, std::string>& map)
481  : hashmap<
482  std::string,
483  std::string,
485  CaseInsensitiveEqual>(map) {}
486 
487  Headers(std::map<std::string, std::string>&& map)
488  : hashmap<
489  std::string,
490  std::string,
493 
494  Headers(std::initializer_list<std::pair<std::string, std::string>> list)
495  : hashmap<
496  std::string,
497  std::string,
500 
501  template <typename T>
502  Result<T> get() const
503  {
504  Option<std::string> value = get(T::NAME);
505  if (value.isNone()) {
506  return None();
507  }
508  Try<T> header = T::create(value.get());
509  if (header.isError()) {
510  return Error(header.error());
511  }
512  return header.get();
513  }
514 
515  Option<std::string> get(const std::string& key) const
516  {
517  return hashmap<
518  std::string,
519  std::string,
522  }
523 
524  Headers operator+(const Headers& that) const
525  {
526  Headers result = *this;
527  result.insert(that.begin(), that.end());
528  return result;
529  }
530 };
531 
532 
533 struct Request
534 {
536  : keepAlive(false), type(BODY), received(Clock::now()) {}
537 
538  std::string method;
539 
540  // TODO(benh): Add major/minor version.
541 
542  // For client requests, the URL should be a URI.
543  // For server requests, the URL may be a URI or a relative reference.
545 
547 
548  // TODO(bmahler): Ensure this is consistent with the 'Connection'
549  // header; perhaps make this a function that checks the header.
550  //
551  // TODO(anand): Ideally, this could default to 'true' since
552  // persistent connections are the default since HTTP 1.1.
553  // Perhaps, we need to go from `keepAlive` to `closeConnection`
554  // to reflect the header more accurately, and to have an
555  // intuitive default of false.
556  //
557  // Default: false.
558  bool keepAlive;
559 
560  // For server requests, this contains the address of the client.
561  // Note that this may correspond to a proxy or load balancer address.
563 
564  // Clients can choose to provide the entire body at once
565  // via BODY or can choose to stream the body over to the
566  // server via PIPE.
567  //
568  // Default: BODY.
569  enum
570  {
572  PIPE
573  } type;
574 
575  // TODO(bmahler): Add a 'query' field which contains both
576  // the URL query and the parsed form data from the body.
577 
578  std::string body;
580 
582 
587  bool acceptsEncoding(const std::string& encoding) const;
588 
593  bool acceptsMediaType(const std::string& mediaType) const;
594 
601  bool acceptsMediaType(
602  const std::string& name,
603  const std::string& mediaType) const;
604 
605 private:
606  bool _acceptsMediaType(
608  const std::string& mediaType) const;
609 };
610 
611 
612 struct Response
613 {
615  : type(NONE) {}
616 
617  Response(uint16_t _code)
618  : type(NONE), code(_code)
619  {
620  status = Status::string(code);
621  }
622 
623  explicit Response(
624  std::string _body,
625  uint16_t _code,
626  const std::string& contentType = "text/plain; charset=utf-8")
627  : type(BODY),
628  body(std::move(_body)),
629  code(_code)
630  {
631  headers["Content-Length"] = stringify(body.size());
632  headers["Content-Type"] = contentType;
633  status = Status::string(code);
634  }
635 
636  // TODO(benh): Add major/minor version.
637  std::string status;
638 
640 
641  // Either provide a 'body', an absolute 'path' to a file, or a
642  // 'pipe' for streaming a response. Distinguish between the cases
643  // using 'type' below.
644  //
645  // BODY: Uses 'body' as the body of the response. These may be
646  // encoded using gzip for efficiency, if 'Content-Encoding' is not
647  // already specified.
648  //
649  // PATH: Attempts to perform a 'sendfile' operation on the file
650  // found at 'path'.
651  //
652  // PIPE: Splices data from the Pipe 'reader' using a "chunked"
653  // 'Transfer-Encoding'. The writer uses a Pipe::Writer to
654  // perform writes and to detect a closed read-end of the Pipe
655  // (i.e. nobody is listening any longer). Once the writer is
656  // finished, it will close its end of the pipe to signal end
657  // of file to the Reader.
658  //
659  // In all cases (BODY, PATH, PIPE), you are expected to properly
660  // specify the 'Content-Type' header, but the 'Content-Length' and
661  // or 'Transfer-Encoding' headers will be filled in for you.
662  enum
663  {
667  PIPE
668  } type;
669 
670  std::string body;
671  std::string path;
673 
674  uint16_t code;
675 };
676 
677 
678 struct OK : Response
679 {
680  OK()
681  : Response(Status::OK) {}
682 
683  explicit OK(const char* body)
684  : Response(std::string(body), Status::OK) {}
685 
686  explicit OK(std::string body)
687  : Response(std::move(body), Status::OK) {}
688 
689  explicit OK(std::string body, const std::string& contentType)
690  : Response(std::move(body), Status::OK, contentType) {}
691 
692  OK(const JSON::Value& value, const Option<std::string>& jsonp = None());
693 
694  OK(JSON::Proxy&& value, const Option<std::string>& jsonp = None());
695 };
696 
697 
699 {
701  : Response(Status::ACCEPTED) {}
702 
703  explicit Accepted(std::string body)
704  : Response(std::move(body), Status::ACCEPTED) {}
705 };
706 
707 
709 {
710  explicit TemporaryRedirect(const std::string& url)
711  : Response(Status::TEMPORARY_REDIRECT)
712  {
713  headers["Location"] = url;
714  }
715 };
716 
717 
719 {
721  : BadRequest("400 Bad Request.") {}
722 
723  explicit BadRequest(std::string body)
724  : Response(std::move(body), Status::BAD_REQUEST) {}
725 };
726 
727 
729 {
730  explicit Unauthorized(const std::vector<std::string>& challenges)
731  : Unauthorized(challenges, "401 Unauthorized.") {}
732 
734  const std::vector<std::string>& challenges,
735  std::string body)
736  : Response(std::move(body), Status::UNAUTHORIZED)
737  {
738  // TODO(arojas): Many HTTP client implementations do not support
739  // multiple challenges within a single 'WWW-Authenticate' header.
740  // Once MESOS-3306 is fixed, we can use multiple entries for the
741  // same header.
742  headers["WWW-Authenticate"] = strings::join(", ", challenges);
743  }
744 };
745 
746 
748 {
750  : Forbidden("403 Forbidden.") {}
751 
752  explicit Forbidden(std::string body)
753  : Response(std::move(body), Status::FORBIDDEN) {}
754 };
755 
756 
758 {
760  : NotFound("404 Not Found.") {}
761 
762  explicit NotFound(std::string body)
763  : Response(std::move(body), Status::NOT_FOUND) {}
764 };
765 
766 
768 {
769  // According to RFC 2616, "An Allow header field MUST be present in a
770  // 405 (Method Not Allowed) response".
771 
773  const std::initializer_list<std::string>& allowedMethods,
774  const Option<std::string>& requestMethod = None())
775  : Response(
776  constructBody(allowedMethods, requestMethod),
777  Status::METHOD_NOT_ALLOWED)
778  {
779  headers["Allow"] = strings::join(", ", allowedMethods);
780  }
781 
782 private:
783  static std::string constructBody(
784  const std::initializer_list<std::string>& allowedMethods,
785  const Option<std::string>& requestMethod)
786  {
787  return
788  "405 Method Not Allowed. Expecting one of { '" +
789  strings::join("', '", allowedMethods) + "' }" +
790  (requestMethod.isSome()
791  ? ", but received '" + requestMethod.get() + "'"
792  : "") +
793  ".";
794  }
795 };
796 
797 
799 {
801  : NotAcceptable("406 Not Acceptable.") {}
802 
803  explicit NotAcceptable(std::string body)
804  : Response(std::move(body), Status::NOT_ACCEPTABLE) {}
805 };
806 
807 
809 {
811  : Conflict("409 Conflict.") {}
812 
813  explicit Conflict(std::string body)
814  : Response(std::move(body), Status::CONFLICT) {}
815 };
816 
817 
819 {
821  : PreconditionFailed("412 Precondition Failed.") {}
822 
823  explicit PreconditionFailed(std::string body)
824  : Response(std::move(body), Status::PRECONDITION_FAILED) {}
825 };
826 
827 
829 {
831  : UnsupportedMediaType("415 Unsupported Media Type.") {}
832 
833  explicit UnsupportedMediaType(std::string body)
834  : Response(std::move(body), Status::UNSUPPORTED_MEDIA_TYPE) {}
835 };
836 
837 
839 {
841  : InternalServerError("500 Internal Server Error.") {}
842 
843  explicit InternalServerError(std::string body)
844  : Response(std::move(body), Status::INTERNAL_SERVER_ERROR) {}
845 };
846 
847 
849 {
851  : NotImplemented("501 Not Implemented.") {}
852 
853  explicit NotImplemented(std::string body)
854  : Response(std::move(body), Status::NOT_IMPLEMENTED) {}
855 };
856 
857 
859 {
861  : ServiceUnavailable("503 Service Unavailable.") {}
862 
863  explicit ServiceUnavailable(std::string body)
864  : Response(std::move(body), Status::SERVICE_UNAVAILABLE) {}
865 };
866 
867 
868 namespace path {
869 
870 // Parses an HTTP path into a map given a pattern (TODO(benh): Make
871 // the patterns be regular expressions). This returns an error if
872 // 'pattern' doesn't match 'path'. For example:
873 //
874 // parse("/books/{isbn}/chapters/{chapter}",
875 // "/books/0304827484/chapters/3")
876 //
877 // Would return a map with the following:
878 // books: "books"
879 // isbn: "0304827484"
880 // chapters: "chapters"
881 // chapter: "3"
882 //
883 // Another example:
884 //
885 // parse("/books/{isbn}/chapters/{chapter}",
886 // "/books/0304827484")
887 //
888 // Would return a map with the following:
889 // books: "books"
890 // isbn: "0304827484"
891 //
892 // And another:
893 //
894 // parse("/books/{isbn}/chapters/{chapter}",
895 // "/books/0304827484/chapters")
896 //
897 // Would return a map with the following:
898 // books: "books"
899 // isbn: "0304827484"
900 // chapters: "chapters"
902  const std::string& pattern,
903  const std::string& path);
904 
905 } // namespace path {
906 
907 
917 std::string encode(
918  const std::string& s,
919  const std::string& additional_chars = "");
920 
921 
922 // Decodes a percent-encoded string according to RFC 3986.
923 // The input string must not already be decoded.
924 // Returns error on the occurrence of a malformed % escape in s.
925 Try<std::string> decode(const std::string& s);
926 
927 
933 Try<std::vector<Response>> decodeResponses(const std::string& s);
934 
935 
936 namespace query {
937 
938 // Decodes an HTTP query string into a map. For example:
939 //
940 // decode("foo=1&bar=%20&baz&foo=3")
941 //
942 // Would return a map with the following:
943 // bar: " "
944 // baz: ""
945 // foo: "3"
946 //
947 // We use the last value for a key for simplicity, since the RFC does not
948 // specify how to handle duplicate keys:
949 // http://en.wikipedia.org/wiki/Query_string
950 // TODO(bmahler): If needed, investigate populating the query map inline
951 // for better performance.
952 Try<hashmap<std::string, std::string>> decode(const std::string& query);
953 
954 std::string encode(const hashmap<std::string, std::string>& query);
955 
956 } // namespace query {
957 
958 
966 {
967 public:
968  Connection() = delete;
969 
977  Future<Response> send(const Request& request, bool streamedResponse = false);
978 
982  Future<Nothing> disconnect();
983 
987  Future<Nothing> disconnected();
988 
989  bool operator==(const Connection& c) const { return data == c.data; }
990  bool operator!=(const Connection& c) const { return !(*this == c); }
991 
994 
995 private:
996  Connection(
997  const network::Socket& s,
998  const network::Address& _localAddress,
999  const network::Address& _peerAddress);
1000 
1001  friend Future<Connection> connect(
1002  const network::Address& address,
1003  Scheme scheme,
1004  const Option<std::string>& peer_hostname);
1005  friend Future<Connection> connect(const URL&);
1006 
1007  // Forward declaration.
1008  struct Data;
1009 
1010  std::shared_ptr<Data> data;
1011 };
1012 
1013 
1015  const network::Address& address,
1016  Scheme scheme,
1017  const Option<std::string>& peer_hostname);
1018 
1019 
1021 
1022 
1023 Future<Connection> connect(const URL& url);
1024 
1025 
1026 namespace internal {
1027 
1029  network::Socket s,
1030  std::function<Future<Response>(const Request&)>&& f);
1031 
1032 } // namespace internal {
1033 
1034 
1035 // Serves HTTP requests on the specified socket using the specified
1036 // handler.
1037 //
1038 // Returns `Nothing` after serving has completed, either because (1) a
1039 // failure occurred receiving requests or sending responses or (2) the
1040 // HTTP connection was not persistent (i.e., a 'Connection: close'
1041 // header existed either on the request or the response) or (3)
1042 // serving was discarded.
1043 //
1044 // Doing a `discard()` on the Future returned from `serve` will
1045 // discard any current socket receiving and any current socket
1046 // sending and shutdown the socket in both directions.
1047 //
1048 // NOTE: HTTP pipelining is automatically performed. If you don't want
1049 // pipelining you must explicitly sequence/serialize the requests to
1050 // wait for previous responses yourself.
1051 //
1052 // NOTE: The `Request` passed to the handler is of type `PIPE` and should
1053 // always be read using `Request.reader`.
1054 template <typename F>
1056 {
1057  return internal::serve(
1058  s,
1059  std::function<Future<Response>(const Request&)>(std::forward<F>(f)));
1060 }
1061 
1062 
1063 // Forward declaration.
1064 class ServerProcess;
1065 
1066 
1067 class Server
1068 {
1069 public:
1070  // Options for creating a server.
1071  //
1072  // NOTE: until GCC 5.0 default member initializers prevented the
1073  // class from being an aggregate which prevented you from being able
1074  // to use aggregate initialization, thus we introduce and use
1075  // `DEFAULT_CREATE_OPTIONS` for the default parameter of `create`.
1077  {
1079  size_t backlog;
1080  };
1081 
1083  {
1084  return {
1085  /* .scheme = */ Scheme::HTTP,
1086  /* .backlog = */ 16384,
1087  };
1088  };
1089 
1090  // Options for stopping a server.
1091  //
1092  // NOTE: see note above as to why we have `DEFAULT_STOP_OPTIONS`.
1094  {
1095  // During the grace period:
1096  // * No new sockets will be accepted (but on OS X they'll still queue).
1097  // * Existing sockets will be shut down for reads to prevent new
1098  // requests from arriving.
1099  // * Existing sockets will be shut down after already received
1100  // requests have their responses sent.
1101  // After the grace period connections will be forcibly shut down.
1103  };
1104 
1106  {
1107  return {
1108  /* .grace_period = */ Seconds(0),
1109  };
1110  };
1111 
1112  static Try<Server> create(
1114  std::function<Future<Response>(
1115  const network::Socket& socket,
1116  const Request&)>&& f,
1117  const CreateOptions& options = DEFAULT_CREATE_OPTIONS());
1118 
1119  template <typename F>
1121  network::Socket socket,
1122  F&& f,
1123  const CreateOptions& options = DEFAULT_CREATE_OPTIONS())
1124  {
1125  return create(
1126  std::move(socket),
1127  std::function<Future<Response>(
1128  const network::Socket&,
1129  const Request&)>(std::forward<F>(f)),
1130  options);
1131  }
1132 
1133  static Try<Server> create(
1134  const network::Address& address,
1135  std::function<Future<Response>(
1136  const network::Socket&,
1137  const Request&)>&& f,
1138  const CreateOptions& options = DEFAULT_CREATE_OPTIONS());
1139 
1140  template <typename F>
1142  const network::Address& address,
1143  F&& f,
1144  const CreateOptions& options = DEFAULT_CREATE_OPTIONS())
1145  {
1146  return create(
1147  address,
1148  std::function<Future<Response>(
1149  const network::Socket&,
1150  const Request&)>(std::forward<F>(f)),
1151  options);
1152  }
1153 
1154  // Movable but not copyable, not assignable.
1155  Server(Server&& that) = default;
1156  Server(const Server&) = delete;
1157  Server& operator=(const Server&) = delete;
1158 
1159  ~Server();
1160 
1161  // Runs the server, returns nothing after the server has been
1162  // stopped or a failure if one occured.
1163  Future<Nothing> run();
1164 
1165  // Returns after the server has been stopped and all existing
1166  // connections have been closed.
1167  Future<Nothing> stop(const StopOptions& options = DEFAULT_STOP_OPTIONS());
1168 
1169  // Returns the bound address of the server.
1171 
1172 private:
1173  Server(
1174  network::Socket&& socket,
1175  std::function<Future<Response>(
1176  const network::Socket&,
1177  const Request&)>&& f);
1178 
1181 };
1182 
1183 
1184 // Create a http Request from the specified parameters.
1186  const UPID& upid,
1187  const std::string& method,
1188  bool enableSSL = false,
1189  const Option<std::string>& path = None(),
1190  const Option<Headers>& headers = None(),
1191  const Option<std::string>& body = None(),
1192  const Option<std::string>& contentType = None());
1193 
1194 
1196  const URL& url,
1197  const std::string& method,
1198  const Option<Headers>& headers = None(),
1199  const Option<std::string>& body = None(),
1200  const Option<std::string>& contentType = None());
1201 
1211  const Request& request,
1212  bool streamedResponse = false);
1213 
1214 
1215 // TODO(Yongqiao Wang): Refactor other functions
1216 // (such as post/get/requestDelete) to use the 'request' function.
1217 
1218 // TODO(bmahler): Support discarding the future responses;
1219 // discarding should disconnect from the server.
1220 
1221 // TODO(joerg84): Make names consistent (see Mesos-3256).
1222 
1223 // Asynchronously sends an HTTP GET request to the specified URL
1224 // and returns the HTTP response of type 'BODY' once the entire
1225 // response is received.
1226 Future<Response> get(
1227  const URL& url,
1228  const Option<Headers>& headers = None());
1229 
1230 
1231 // Asynchronously sends an HTTP GET request to the process with the
1232 // given UPID and returns the HTTP response of type 'BODY' once the
1233 // entire response is received.
1234 Future<Response> get(
1235  const UPID& upid,
1236  const Option<std::string>& path = None(),
1237  const Option<std::string>& query = None(),
1238  const Option<Headers>& headers = None(),
1239  const Option<std::string>& scheme = None());
1240 
1241 
1242 // Asynchronously sends an HTTP POST request to the specified URL
1243 // and returns the HTTP response of type 'BODY' once the entire
1244 // response is received.
1246  const URL& url,
1247  const Option<Headers>& headers = None(),
1248  const Option<std::string>& body = None(),
1249  const Option<std::string>& contentType = None());
1250 
1251 
1252 // Asynchronously sends an HTTP POST request to the process with the
1253 // given UPID and returns the HTTP response of type 'BODY' once the
1254 // entire response is received.
1256  const UPID& upid,
1257  const Option<std::string>& path = None(),
1258  const Option<Headers>& headers = None(),
1259  const Option<std::string>& body = None(),
1260  const Option<std::string>& contentType = None(),
1261  const Option<std::string>& scheme = None());
1262 
1263 
1273  const URL& url,
1274  const Option<Headers>& headers = None());
1275 
1276 
1289  const UPID& upid,
1290  const Option<std::string>& path = None(),
1291  const Option<Headers>& headers = None(),
1292  const Option<std::string>& scheme = None());
1293 
1294 
1295 namespace streaming {
1296 
1297 // Asynchronously sends an HTTP GET request to the specified URL
1298 // and returns the HTTP response of type 'PIPE' once the response
1299 // headers are received. The caller must read the response body
1300 // from the Pipe::Reader.
1301 Future<Response> get(
1302  const URL& url,
1303  const Option<Headers>& headers = None());
1304 
1305 // Asynchronously sends an HTTP GET request to the process with the
1306 // given UPID and returns the HTTP response of type 'PIPE' once the
1307 // response headers are received. The caller must read the response
1308 // body from the Pipe::Reader.
1309 Future<Response> get(
1310  const UPID& upid,
1311  const Option<std::string>& path = None(),
1312  const Option<std::string>& query = None(),
1313  const Option<Headers>& headers = None(),
1314  const Option<std::string>& scheme = None());
1315 
1316 // Asynchronously sends an HTTP POST request to the specified URL
1317 // and returns the HTTP response of type 'PIPE' once the response
1318 // headers are received. The caller must read the response body
1319 // from the Pipe::Reader.
1321  const URL& url,
1322  const Option<Headers>& headers = None(),
1323  const Option<std::string>& body = None(),
1324  const Option<std::string>& contentType = None());
1325 
1326 // Asynchronously sends an HTTP POST request to the process with the
1327 // given UPID and returns the HTTP response of type 'PIPE' once the
1328 // response headers are received. The caller must read the response
1329 // body from the Pipe::Reader.
1331  const UPID& upid,
1332  const Option<std::string>& path = None(),
1333  const Option<Headers>& headers = None(),
1334  const Option<std::string>& body = None(),
1335  const Option<std::string>& contentType = None(),
1336  const Option<std::string>& scheme = None());
1337 
1338 } // namespace streaming {
1339 
1340 } // namespace http {
1341 } // namespace process {
1342 
1343 #endif // __PROCESS_HTTP_HPP__
static StopOptions DEFAULT_STOP_OPTIONS()
Definition: http.hpp:1105
Definition: path.hpp:29
Try< hashmap< std::string, std::string > > parse(const std::string &pattern, const std::string &path)
bool operator!=(const Writer &other) const
Definition: http.hpp:379
WWWAuthenticate(const std::string &authScheme, const hashmap< std::string, std::string > &authParam)
Definition: http.hpp:444
size_t operator()(const std::string &key) const
Definition: http.hpp:199
Future< Nothing > serve(network::Socket s, std::function< Future< Response >(const Request &)> &&f)
Forbidden()
Definition: http.hpp:749
bool operator!=(const Connection &c) const
Definition: http.hpp:990
static const uint16_t GATEWAY_TIMEOUT
Definition: http.hpp:267
static const uint16_t MOVED_PERMANENTLY
Definition: http.hpp:239
NotImplemented(std::string body)
Definition: http.hpp:853
static const uint16_t GONE
Definition: http.hpp:255
static const uint16_t UNSUPPORTED_MEDIA_TYPE
Definition: http.hpp:260
Definition: errorbase.hpp:36
Definition: http.hpp:1076
Definition: option.hpp:29
Definition: http.hpp:309
static const uint16_t METHOD_NOT_ALLOWED
Definition: http.hpp:250
Future< Response > request(const Request &request, bool streamedResponse=false)
Asynchronously sends an HTTP request to the process and returns the HTTP response once the entire res...
F && f
Definition: defer.hpp:270
static const uint16_t BAD_REQUEST
Definition: http.hpp:245
Conflict(std::string body)
Definition: http.hpp:813
static const uint16_t NO_CONTENT
Definition: http.hpp:235
T & get()&
Definition: try.hpp:80
URL url
Definition: http.hpp:544
static const uint16_t REQUEST_TIMEOUT
Definition: http.hpp:253
static const uint16_t LENGTH_REQUIRED
Definition: http.hpp:256
std::stringstream & join(std::stringstream &stream, const std::string &separator, T &&...args)
Definition: strings.hpp:307
static CreateOptions DEFAULT_CREATE_OPTIONS()
Definition: http.hpp:1082
Definition: check.hpp:33
std::string status
Definition: http.hpp:637
InternalServerError(std::string body)
Definition: http.hpp:843
NotAcceptable()
Definition: http.hpp:800
ServiceUnavailable(std::string body)
Definition: http.hpp:863
static const uint16_t PARTIAL_CONTENT
Definition: http.hpp:237
static const uint16_t EXPECTATION_FAILED
Definition: http.hpp:262
static const uint16_t CONFLICT
Definition: http.hpp:254
Provides timers.
Definition: clock.hpp:37
Option< Pipe::Reader > reader
Definition: http.hpp:579
Unauthorized(const std::vector< std::string > &challenges)
Definition: http.hpp:730
uint16_t code
Definition: http.hpp:674
Definition: http.hpp:197
Definition: http.hpp:227
Unauthorized(const std::vector< std::string > &challenges, std::string body)
Definition: http.hpp:733
OK()
Definition: http.hpp:680
Future< Nothing > serve(const network::Socket &s, F &&f)
Definition: http.hpp:1055
Definition: http.hpp:848
static const uint16_t NON_AUTHORITATIVE_INFORMATION
Definition: http.hpp:234
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: http.hpp:210
Option< std::string > domain
Definition: http.hpp:185
InternalServerError()
Definition: http.hpp:840
Definition: http.hpp:1067
static const uint16_t FOUND
Definition: http.hpp:240
OK(std::string body, const std::string &contentType)
Definition: http.hpp:689
bool operator==(const Writer &other) const
Definition: http.hpp:378
Definition: type_utils.hpp:598
Definition: address.hpp:324
Future< Response > get(const URL &url, const Option< Headers > &headers=None())
Definition: http.hpp:571
Option< network::Address > client
Definition: http.hpp:562
const std::string NAME
Definition: logrotate.hpp:38
static const uint16_t MULTIPLE_CHOICES
Definition: http.hpp:238
static const uint16_t REQUEST_ENTITY_TOO_LARGE
Definition: http.hpp:258
Definition: http.hpp:664
Future< Response > requestDelete(const URL &url, const Option< Headers > &headers=None())
Asynchronously sends an HTTP DELETE request to the process with the given UPID and returns the HTTP r...
std::string encode(const std::string &s, const std::string &additional_chars="")
Returns a percent-encoded string according to RFC 3986.
Definition: http.hpp:708
Option< net::IP > ip
Definition: http.hpp:186
URL(const std::string &_scheme, const std::string &_domain, const std::string &_path, const hashmap< std::string, std::string > &_query=(hashmap< std::string, std::string >()), const Option< std::string > &_fragment=None())
Definition: http.hpp:134
Definition: duration.hpp:32
Try< std::string > decode(const std::string &s)
Decode a string that is Base64-encoded with the standard Base64 alphabet.
Definition: base64.hpp:183
Definition: check.hpp:30
BadRequest()
Definition: http.hpp:720
PreconditionFailed(std::string body)
Definition: http.hpp:823
static const uint16_t RESET_CONTENT
Definition: http.hpp:236
bool isSome() const
Definition: option.hpp:116
Definition: http.hpp:533
OK(std::string body)
Definition: http.hpp:686
PreconditionFailed()
Definition: http.hpp:820
Scheme
Definition: http.hpp:56
bool operator==(const Connection &c) const
Definition: http.hpp:989
ServiceUnavailable()
Definition: http.hpp:860
hashmap< std::string, std::string > query
Definition: http.hpp:189
Definition: http.hpp:665
Definition: ip.hpp:73
Definition: hashmap.hpp:38
Duration grace_period
Definition: http.hpp:1102
Accepted()
Definition: http.hpp:700
Response(std::string _body, uint16_t _code, const std::string &contentType="text/plain; charset=utf-8")
Definition: http.hpp:623
Option< Pipe::Reader > reader
Definition: http.hpp:672
std::string path
Definition: http.hpp:188
Definition: http.hpp:808
Definition: http.hpp:767
static const uint16_t PRECONDITION_FAILED
Definition: http.hpp:257
std::string body
Definition: http.hpp:670
An "untyped" PID, used to encapsulate the process ID for lower-layer abstractions (eg...
Definition: pid.hpp:39
Definition: http.hpp:130
static const uint16_t NOT_ACCEPTABLE
Definition: http.hpp:251
Option< std::string > scheme
Definition: http.hpp:182
Definition: http.hpp:698
Future< Nothing > setAuthenticator(const std::string &realm, Owned< Authenticator > authenticator)
Sets (or overwrites) the authenticator for the realm.
NotImplemented()
Definition: http.hpp:850
OK(const char *body)
Definition: http.hpp:683
static const uint16_t SERVICE_UNAVAILABLE
Definition: http.hpp:266
Definition: http.hpp:354
Try<::mesos::Value::Ranges > fragment(const ::mesos::Value::Range &bounds, size_t numRanges)
Definition: jsonify.hpp:86
Definition: duration.hpp:207
static const uint16_t PAYMENT_REQUIRED
Definition: http.hpp:247
URL(const std::string &_scheme, const net::IP &_ip, const uint16_t _port=80, const std::string &_path="/", const hashmap< std::string, std::string > &_query=(hashmap< std::string, std::string >()), const Option< std::string > &_fragment=None())
Definition: http.hpp:160
Definition: http.hpp:471
static const uint16_t USE_PROXY
Definition: http.hpp:243
Option< uint16_t > port
Definition: http.hpp:187
NotAcceptable(std::string body)
Definition: http.hpp:803
Headers(std::map< std::string, std::string > &&map)
Definition: http.hpp:487
static const uint16_t ACCEPTED
Definition: http.hpp:233
NotFound()
Definition: http.hpp:759
const T & get() const &
Definition: option.hpp:119
Definition: http.hpp:798
Future< Response > post(const URL &url, const Option< Headers > &headers=None(), const Option< std::string > &body=None(), const Option< std::string > &contentType=None())
Request createRequest(const UPID &upid, const std::string &method, bool enableSSL=false, const Option< std::string > &path=None(), const Option< Headers > &headers=None(), const Option< std::string > &body=None(), const Option< std::string > &contentType=None())
Definition: http.hpp:838
bool keepAlive
Definition: http.hpp:558
bool operator==(const Pipe &other) const
Definition: http.hpp:403
static const uint16_t SEE_OTHER
Definition: http.hpp:241
bool operator!=(const Reader &other) const
Definition: http.hpp:337
static const uint16_t OK
Definition: http.hpp:231
Definition: http.hpp:858
URL(const std::string &_scheme, const std::string &_domain, const uint16_t _port=80, const std::string &_path="/", const hashmap< std::string, std::string > &_query=(hashmap< std::string, std::string >()), const Option< std::string > &_fragment=None())
Definition: http.hpp:146
static Try error(const E &e)
Definition: try.hpp:43
Scheme scheme
Definition: http.hpp:1078
UnsupportedMediaType(std::string body)
Definition: http.hpp:833
Future< R > run(R(*method)())
Definition: run.hpp:55
Definition: time.hpp:23
Conflict()
Definition: http.hpp:810
Option< std::string > fragment
Definition: http.hpp:190
static const uint16_t CONTINUE
Definition: http.hpp:229
Try< std::vector< Entry > > list(const std::string &hierarchy, const std::string &cgroup)
static const uint16_t PROXY_AUTHENTICATION_REQUIRED
Definition: http.hpp:252
Definition: json.hpp:247
Future< Connection > connect(const network::Address &address, Scheme scheme, const Option< std::string > &peer_hostname)
Iterable< V > map(F &&f, const Iterable< U, Us... > &input)
Definition: lambda.hpp:46
Result< Process > process(pid_t pid)
Definition: freebsd.hpp:30
Definition: http.hpp:818
bool operator!=(const Pipe &other) const
Definition: http.hpp:404
NotFound(std::string body)
Definition: http.hpp:762
Definition: none.hpp:27
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:78
Result< Credentials > read(const Path &path)
Definition: credentials.hpp:35
std::string path
Definition: http.hpp:671
TemporaryRedirect(const std::string &url)
Definition: http.hpp:710
std::string method
Definition: http.hpp:538
Definition: executor.hpp:48
Definition: http.hpp:612
std::ostream & operator<<(std::ostream &stream, const URL &url)
Pipe()
Definition: http.hpp:396
Definition: http.hpp:828
Headers operator+(const Headers &that) const
Definition: http.hpp:524
std::string body
Definition: http.hpp:578
static const uint16_t SWITCHING_PROTOCOLS
Definition: http.hpp:230
static const uint16_t BAD_GATEWAY
Definition: http.hpp:265
Try< std::vector< Response > > decodeResponses(const std::string &s)
Decode HTTP responses from the given string.
static const uint16_t INTERNAL_SERVER_ERROR
Definition: http.hpp:263
Definition: http.hpp:718
UnsupportedMediaType()
Definition: http.hpp:830
Protocol< WriteRequest, WriteResponse > write
Definition: http.hpp:678
MethodNotAllowed(const std::initializer_list< std::string > &allowedMethods, const Option< std::string > &requestMethod=None())
Definition: http.hpp:772
Headers(const std::map< std::string, std::string > &map)
Definition: http.hpp:480
Try< uint32_t > type(const std::string &path)
network::inet::Address address()
Returns the socket address associated with this instance of the library.
static const uint16_t NOT_MODIFIED
Definition: http.hpp:242
Definition: http.hpp:728
static Try< Server > create(network::Socket socket, F &&f, const CreateOptions &options=DEFAULT_CREATE_OPTIONS())
Definition: http.hpp:1120
bool isNone() const
Definition: option.hpp:117
const network::Address peerAddress
Definition: http.hpp:993
static const uint16_t REQUESTED_RANGE_NOT_SATISFIABLE
Definition: http.hpp:261
void setCallbacks(const AuthorizationCallbacks &)
static const uint16_t CREATED
Definition: http.hpp:232
Try< Nothing > create(const std::string &hierarchy, const std::string &cgroup, bool recursive=false)
Accepted(std::string body)
Definition: http.hpp:703
Definition: http.hpp:666
Response()
Definition: http.hpp:614
static const uint16_t UNAUTHORIZED
Definition: http.hpp:246
static const uint16_t NOT_FOUND
Definition: http.hpp:249
URI http(const std::string &host, const std::string &path="/", const Option< int > &port=None(), const Option< std::string > &query=None(), const Option< std::string > &fragment=None(), const Option< std::string > &user=None(), const Option< std::string > &password=None())
Creates an http URI with the given parameters.
Definition: http.hpp:35
bool operator==(const Reader &other) const
Definition: http.hpp:336
Try< Netlink< struct nl_sock > > socket(int protocol=NETLINK_ROUTE)
Definition: internal.hpp:91
std::string stringify(int flags)
static const uint16_t NOT_IMPLEMENTED
Definition: http.hpp:264
Definition: owned.hpp:36
Time received
Definition: http.hpp:581
static std::string string(uint16_t code)
Headers()
Definition: http.hpp:478
Headers(std::initializer_list< std::pair< std::string, std::string >> list)
Definition: http.hpp:494
BadRequest(std::string body)
Definition: http.hpp:723
Headers headers
Definition: http.hpp:639
Response(uint16_t _code)
Definition: http.hpp:617
const network::Address localAddress
Definition: http.hpp:992
size_t backlog
Definition: http.hpp:1079
static const uint16_t REQUEST_URI_TOO_LARGE
Definition: http.hpp:259
Forbidden(std::string body)
Definition: http.hpp:752
Definition: http.hpp:1093
bool isValidStatus(uint16_t code)
Represents a connection to an HTTP server.
Definition: http.hpp:965
Future< Nothing > unsetAuthenticator(const std::string &realm)
Unsets the authenticator for the realm.
bool operator()(const std::string &left, const std::string &right) const
Definition: http.hpp:212
Definition: http.hpp:315
constexpr const char * name
Definition: shell.hpp:43
static const uint16_t HTTP_VERSION_NOT_SUPPORTED
Definition: http.hpp:268
static Try< Server > create(const network::Address &address, F &&f, const CreateOptions &options=DEFAULT_CREATE_OPTIONS())
Definition: http.hpp:1141
static const uint16_t TEMPORARY_REDIRECT
Definition: http.hpp:244
static const uint16_t FORBIDDEN
Definition: http.hpp:248
Headers headers
Definition: http.hpp:546
Definition: http.hpp:747
Definition: http.hpp:757
Future< size_t > send(const int_fd &fd, const void *buf, size_t size)
Request()
Definition: http.hpp:535