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