• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2012 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #ifndef SHRPX_DOWNSTREAM_H
26 #define SHRPX_DOWNSTREAM_H
27 
28 #include "shrpx.h"
29 
30 #include <cinttypes>
31 #include <vector>
32 #include <string>
33 #include <memory>
34 #include <chrono>
35 #include <algorithm>
36 
37 #include <ev.h>
38 
39 #include <nghttp2/nghttp2.h>
40 
41 #ifdef ENABLE_HTTP3
42 #  include <nghttp3/nghttp3.h>
43 #endif // ENABLE_HTTP3
44 
45 #include "llhttp.h"
46 
47 #include "shrpx_io_control.h"
48 #include "shrpx_log_config.h"
49 #include "http2.h"
50 #include "memchunk.h"
51 #include "allocator.h"
52 
53 using namespace nghttp2;
54 
55 namespace shrpx {
56 
57 class Upstream;
58 class DownstreamConnection;
59 struct BlockedLink;
60 struct DownstreamAddrGroup;
61 struct DownstreamAddr;
62 
63 class FieldStore {
64 public:
FieldStore(BlockAllocator & balloc,size_t headers_initial_capacity)65   FieldStore(BlockAllocator &balloc, size_t headers_initial_capacity)
66       : content_length(-1),
67         balloc_(balloc),
68         buffer_size_(0),
69         header_key_prev_(false),
70         trailer_key_prev_(false) {
71     headers_.reserve(headers_initial_capacity);
72   }
73 
headers()74   const HeaderRefs &headers() const { return headers_; }
trailers()75   const HeaderRefs &trailers() const { return trailers_; }
76 
headers()77   HeaderRefs &headers() { return headers_; }
trailers()78   HeaderRefs &trailers() { return trailers_; }
79 
add_extra_buffer_size(size_t n)80   const void add_extra_buffer_size(size_t n) { buffer_size_ += n; }
buffer_size()81   size_t buffer_size() const { return buffer_size_; }
82 
num_fields()83   size_t num_fields() const { return headers_.size() + trailers_.size(); }
84 
85   // Returns pointer to the header field with the name |name|.  If
86   // multiple header have |name| as name, return last occurrence from
87   // the beginning.  If no such header is found, returns nullptr.
88   const HeaderRefs::value_type *header(int32_t token) const;
89   HeaderRefs::value_type *header(int32_t token);
90   // Returns pointer to the header field with the name |name|.  If no
91   // such header is found, returns nullptr.
92   const HeaderRefs::value_type *header(const StringRef &name) const;
93 
94   void add_header_token(const StringRef &name, const StringRef &value,
95                         bool no_index, int32_t token);
96 
97   // Adds header field name |name|.  First, the copy of header field
98   // name pointed by name.c_str() of length name.size() is made, and
99   // stored.
100   void alloc_add_header_name(const StringRef &name);
101 
102   void append_last_header_key(const char *data, size_t len);
103   void append_last_header_value(const char *data, size_t len);
104 
header_key_prev()105   bool header_key_prev() const { return header_key_prev_; }
106 
107   // Parses content-length, and records it in the field.  If there are
108   // multiple Content-Length, returns -1.
109   int parse_content_length();
110 
111   // Empties headers.
112   void clear_headers();
113 
114   void add_trailer_token(const StringRef &name, const StringRef &value,
115                          bool no_index, int32_t token);
116 
117   // Adds trailer field name |name|.  First, the copy of trailer field
118   // name pointed by name.c_str() of length name.size() is made, and
119   // stored.
120   void alloc_add_trailer_name(const StringRef &name);
121 
122   void append_last_trailer_key(const char *data, size_t len);
123   void append_last_trailer_value(const char *data, size_t len);
124 
trailer_key_prev()125   bool trailer_key_prev() const { return trailer_key_prev_; }
126 
127   // erase_content_length_and_transfer_encoding erases content-length
128   // and transfer-encoding header fields.
129   void erase_content_length_and_transfer_encoding();
130 
131   // content-length, -1 if it is unknown.
132   int64_t content_length;
133 
134 private:
135   BlockAllocator &balloc_;
136   HeaderRefs headers_;
137   // trailer fields.  For HTTP/1.1, trailer fields are only included
138   // with chunked encoding.  For HTTP/2, there is no such limit.
139   HeaderRefs trailers_;
140   // Sum of the length of name and value in headers_ and trailers_.
141   // This could also be increased by add_extra_buffer_size() to take
142   // into account for request URI in case of HTTP/1.x request.
143   size_t buffer_size_;
144   bool header_key_prev_;
145   bool trailer_key_prev_;
146 };
147 
148 // Protocols allowed in HTTP/2 :protocol header field.
149 enum class ConnectProto {
150   NONE,
151   WEBSOCKET,
152 };
153 
154 struct Request {
RequestRequest155   Request(BlockAllocator &balloc)
156       : fs(balloc, 16),
157         recv_body_length(0),
158         unconsumed_body_length(0),
159         method(-1),
160         http_major(1),
161         http_minor(1),
162         connect_proto(ConnectProto::NONE),
163         upgrade_request(false),
164         http2_upgrade_seen(false),
165         connection_close(false),
166         http2_expect_body(false),
167         no_authority(false),
168         forwarded_once(false) {}
169 
consumeRequest170   void consume(size_t len) {
171     assert(unconsumed_body_length >= len);
172     unconsumed_body_length -= len;
173   }
174 
regular_connect_methodRequest175   bool regular_connect_method() const {
176     return method == HTTP_CONNECT && connect_proto == ConnectProto::NONE;
177   }
178 
extended_connect_methodRequest179   bool extended_connect_method() const {
180     return connect_proto != ConnectProto::NONE;
181   }
182 
183   FieldStore fs;
184   // Timestamp when all request header fields are received.
185   std::shared_ptr<Timestamp> tstamp;
186   // Request scheme.  For HTTP/2, this is :scheme header field value.
187   // For HTTP/1.1, this is deduced from URI or connection.
188   StringRef scheme;
189   // Request authority.  This is HTTP/2 :authority header field value
190   // or host header field value.  We may deduce it from absolute-form
191   // HTTP/1 request.  We also store authority-form HTTP/1 request.
192   // This could be empty if request comes from HTTP/1.0 without Host
193   // header field and origin-form.
194   StringRef authority;
195   // Request path, including query component.  For HTTP/1.1, this is
196   // request-target.  For HTTP/2, this is :path header field value.
197   // For CONNECT request, this is empty.
198   StringRef path;
199   // This is original authority which cannot be changed by per-pattern
200   // mruby script.
201   StringRef orig_authority;
202   // This is original path which cannot be changed by per-pattern
203   // mruby script.
204   StringRef orig_path;
205   // the length of request body received so far
206   int64_t recv_body_length;
207   // The number of bytes not consumed by the application yet.
208   size_t unconsumed_body_length;
209   int method;
210   // HTTP major and minor version
211   int http_major, http_minor;
212   // connect_proto specified in HTTP/2 :protocol pseudo header field
213   // which enables extended CONNECT method.  This field is also set if
214   // WebSocket upgrade is requested in h1 frontend for convenience.
215   ConnectProto connect_proto;
216   // Returns true if the request is HTTP upgrade (HTTP Upgrade or
217   // CONNECT method).  Upgrade to HTTP/2 is excluded.  For HTTP/2
218   // Upgrade, check get_http2_upgrade_request().
219   bool upgrade_request;
220   // true if h2c is seen in Upgrade header field.
221   bool http2_upgrade_seen;
222   bool connection_close;
223   // true if this is HTTP/2, and request body is expected.  Note that
224   // we don't take into account HTTP method here.
225   bool http2_expect_body;
226   // true if request does not have any information about authority.
227   // This happens when: For HTTP/2 request, :authority is missing.
228   // For HTTP/1 request, origin or asterisk form is used.
229   bool no_authority;
230   // true if backend selection is done for request once.
231   // orig_authority and orig_path have the authority and path which
232   // are used for the first backend selection.
233   bool forwarded_once;
234 };
235 
236 struct Response {
ResponseResponse237   Response(BlockAllocator &balloc)
238       : fs(balloc, 32),
239         recv_body_length(0),
240         unconsumed_body_length(0),
241         http_status(0),
242         http_major(1),
243         http_minor(1),
244         connection_close(false),
245         headers_only(false) {}
246 
consumeResponse247   void consume(size_t len) {
248     assert(unconsumed_body_length >= len);
249     unconsumed_body_length -= len;
250   }
251 
252   // returns true if a resource denoted by scheme, authority, and path
253   // has already been pushed.
is_resource_pushedResponse254   bool is_resource_pushed(const StringRef &scheme, const StringRef &authority,
255                           const StringRef &path) const {
256     if (!pushed_resources) {
257       return false;
258     }
259     return std::find(std::begin(*pushed_resources), std::end(*pushed_resources),
260                      std::make_tuple(scheme, authority, path)) !=
261            std::end(*pushed_resources);
262   }
263 
264   // remember that a resource denoted by scheme, authority, and path
265   // is pushed.
resource_pushedResponse266   void resource_pushed(const StringRef &scheme, const StringRef &authority,
267                        const StringRef &path) {
268     if (!pushed_resources) {
269       pushed_resources = std::make_unique<
270           std::vector<std::tuple<StringRef, StringRef, StringRef>>>();
271     }
272     pushed_resources->emplace_back(scheme, authority, path);
273   }
274 
275   FieldStore fs;
276   // array of the tuple of scheme, authority, and path of pushed
277   // resource.  This is required because RFC 8297 says that server
278   // typically includes header fields appeared in non-final response
279   // header fields in final response header fields.  Without checking
280   // that a particular resource has already been pushed, or not, we
281   // end up pushing the same resource at least twice.  It is unknown
282   // that we should use more complex data structure (e.g., std::set)
283   // to find the resources faster.
284   std::unique_ptr<std::vector<std::tuple<StringRef, StringRef, StringRef>>>
285       pushed_resources;
286   // the length of response body received so far
287   int64_t recv_body_length;
288   // The number of bytes not consumed by the application yet.  This is
289   // mainly for HTTP/2 backend.
290   size_t unconsumed_body_length;
291   // HTTP status code
292   unsigned int http_status;
293   int http_major, http_minor;
294   bool connection_close;
295   // true if response only consists of HEADERS, and it bears
296   // END_STREAM.  This is used to tell Http2Upstream that it can send
297   // response with single HEADERS with END_STREAM flag only.
298   bool headers_only;
299 };
300 
301 enum class DownstreamState {
302   INITIAL,
303   HEADER_COMPLETE,
304   MSG_COMPLETE,
305   STREAM_CLOSED,
306   CONNECT_FAIL,
307   MSG_RESET,
308   // header contains invalid header field.  We can safely send error
309   // response (502) to a client.
310   MSG_BAD_HEADER,
311   // header fields in HTTP/1 request exceed the configuration limit.
312   // This state is only transitioned from INITIAL state, and solely
313   // used to signal 431 status code to the client.
314   HTTP1_REQUEST_HEADER_TOO_LARGE,
315 };
316 
317 enum class DispatchState {
318   NONE,
319   PENDING,
320   BLOCKED,
321   ACTIVE,
322   FAILURE,
323 };
324 
325 class Downstream {
326 public:
327   Downstream(Upstream *upstream, MemchunkPool *mcpool, int64_t stream_id);
328   ~Downstream();
329   void reset_upstream(Upstream *upstream);
330   Upstream *get_upstream() const;
331   void set_stream_id(int64_t stream_id);
332   int64_t get_stream_id() const;
333   void set_assoc_stream_id(int64_t stream_id);
334   int64_t get_assoc_stream_id() const;
335   void pause_read(IOCtrlReason reason);
336   int resume_read(IOCtrlReason reason, size_t consumed);
337   void force_resume_read();
338   // Set stream ID for downstream HTTP2 connection.
339   void set_downstream_stream_id(int64_t stream_id);
340   int64_t get_downstream_stream_id() const;
341 
342   int attach_downstream_connection(std::unique_ptr<DownstreamConnection> dconn);
343   void detach_downstream_connection();
344   DownstreamConnection *get_downstream_connection();
345   // Returns dconn_ and nullifies dconn_.
346   std::unique_ptr<DownstreamConnection> pop_downstream_connection();
347 
348   // Returns true if output buffer is full. If underlying dconn_ is
349   // NULL, this function always returns false.
350   bool request_buf_full();
351   // Returns true if upgrade (HTTP Upgrade or CONNECT) is succeeded in
352   // h1 backend.  This should not depend on inspect_http1_response().
353   void check_upgrade_fulfilled_http1();
354   // Returns true if upgrade (HTTP Upgrade or CONNECT) is succeeded in
355   // h2 backend.
356   void check_upgrade_fulfilled_http2();
357   // Returns true if the upgrade is succeeded as a result of the call
358   // check_upgrade_fulfilled_http*().  HTTP/2 Upgrade is excluded.
359   bool get_upgraded() const;
360   // Inspects HTTP/2 request.
361   void inspect_http2_request();
362   // Inspects HTTP/1 request.  This checks whether the request is
363   // upgrade request and tranfer-encoding etc.
364   void inspect_http1_request();
365   // Returns true if the request is HTTP Upgrade for HTTP/2
366   bool get_http2_upgrade_request() const;
367   // Returns the value of HTTP2-Settings request header field.
368   StringRef get_http2_settings() const;
369 
370   // downstream request API
request()371   const Request &request() const { return req_; }
request()372   Request &request() { return req_; }
373 
374   // Count number of crumbled cookies
375   size_t count_crumble_request_cookie();
376   // Crumbles (split cookie by ";") in request_headers_ and adds them
377   // in |nva|.  Headers::no_index is inherited.
378   void crumble_request_cookie(std::vector<nghttp2_nv> &nva);
379   // Assembles request cookies.  The opposite operation against
380   // crumble_request_cookie().
381   StringRef assemble_request_cookie();
382 
383   void
384   set_request_start_time(std::chrono::high_resolution_clock::time_point time);
385   const std::chrono::high_resolution_clock::time_point &
386   get_request_start_time() const;
387   int push_request_headers();
388   bool get_chunked_request() const;
389   void set_chunked_request(bool f);
390   int push_upload_data_chunk(const uint8_t *data, size_t datalen);
391   int end_upload_data();
392   // Validates that received request body length and content-length
393   // matches.
394   bool validate_request_recv_body_length() const;
395   void set_request_downstream_host(const StringRef &host);
396   bool expect_response_body() const;
397   bool expect_response_trailer() const;
398   void set_request_state(DownstreamState state);
399   DownstreamState get_request_state() const;
400   DefaultMemchunks *get_request_buf();
401   void set_request_pending(bool f);
402   bool get_request_pending() const;
403   void set_request_header_sent(bool f);
404   bool get_request_header_sent() const;
405   // Returns true if request is ready to be submitted to downstream.
406   // When sending pending request, get_request_pending() should be
407   // checked too because this function may return true when
408   // get_request_pending() returns false.
409   bool request_submission_ready() const;
410 
411   DefaultMemchunks *get_blocked_request_buf();
412   bool get_blocked_request_data_eof() const;
413   void set_blocked_request_data_eof(bool f);
414 
415   // downstream response API
response()416   const Response &response() const { return resp_; }
response()417   Response &response() { return resp_; }
418 
419   // Rewrites the location response header field.
420   void rewrite_location_response_header(const StringRef &upstream_scheme);
421 
422   bool get_chunked_response() const;
423   void set_chunked_response(bool f);
424 
425   void set_response_state(DownstreamState state);
426   DownstreamState get_response_state() const;
427   DefaultMemchunks *get_response_buf();
428   bool response_buf_full();
429   // Validates that received response body length and content-length
430   // matches.
431   bool validate_response_recv_body_length() const;
432   uint32_t get_response_rst_stream_error_code() const;
433   void set_response_rst_stream_error_code(uint32_t error_code);
434   // Inspects HTTP/1 response.  This checks tranfer-encoding etc.
435   void inspect_http1_response();
436   // Clears some of member variables for response.
437   void reset_response();
438   // True if the response is non-final (1xx status code).  Note that
439   // if connection was upgraded, 101 status code is treated as final.
440   bool get_non_final_response() const;
441   // True if protocol version used by client supports non final
442   // response.  Only HTTP/1.1 and HTTP/2 clients support it.
443   bool supports_non_final_response() const;
444   void set_expect_final_response(bool f);
445   bool get_expect_final_response() const;
446 
447   // Call this method when there is incoming data in downstream
448   // connection.
449   int on_read();
450 
451   // Resets upstream read timer.  If it is active, timeout value is
452   // reset.  If it is not active, timer will be started.
453   void reset_upstream_rtimer();
454   // Resets upstream write timer. If it is active, timeout value is
455   // reset.  If it is not active, timer will be started.  This
456   // function also resets read timer if it has been started.
457   void reset_upstream_wtimer();
458   // Makes sure that upstream write timer is started.  If it has been
459   // started, do nothing.  Otherwise, write timer will be started.
460   void ensure_upstream_wtimer();
461   // Disables upstream read timer.
462   void disable_upstream_rtimer();
463   // Disables upstream write timer.
464   void disable_upstream_wtimer();
465 
466   // Downstream timer functions.  They works in a similar way just
467   // like the upstream timer function.
468   void reset_downstream_rtimer();
469   void reset_downstream_wtimer();
470   void ensure_downstream_wtimer();
471   void disable_downstream_rtimer();
472   void disable_downstream_wtimer();
473 
474   // Returns true if accesslog can be written for this downstream.
475   bool accesslog_ready() const;
476 
477   // Increment retry count
478   void add_retry();
479   // true if retry attempt should not be done.
480   bool no_more_retry() const;
481 
482   DispatchState get_dispatch_state() const;
483   void set_dispatch_state(DispatchState s);
484 
485   void attach_blocked_link(BlockedLink *l);
486   BlockedLink *detach_blocked_link();
487 
488   // Returns true if downstream_connection can be detached and reused.
489   bool can_detach_downstream_connection() const;
490 
491   DefaultMemchunks pop_response_buf();
492 
493   BlockAllocator &get_block_allocator();
494 
495   void add_rcbuf(nghttp2_rcbuf *rcbuf);
496 #ifdef ENABLE_HTTP3
497   void add_rcbuf(nghttp3_rcbuf *rcbuf);
498 #endif // ENABLE_HTTP3
499 
500   void
501   set_downstream_addr_group(const std::shared_ptr<DownstreamAddrGroup> &group);
502   void set_addr(const DownstreamAddr *addr);
503 
504   const DownstreamAddr *get_addr() const;
505 
506   void set_accesslog_written(bool f);
507 
508   // Finds affinity cookie from request header fields.  The name of
509   // cookie is given in |name|.  If an affinity cookie is found, it is
510   // assigned to a member function, and is returned.  If it is not
511   // found, or is malformed, returns 0.
512   uint32_t find_affinity_cookie(const StringRef &name);
513   // Set |h| as affinity cookie.
514   void renew_affinity_cookie(uint32_t h);
515   // Returns affinity cookie to send.  If it does not need to be sent,
516   // for example, because the value is retrieved from a request header
517   // field, returns 0.
518   uint32_t get_affinity_cookie_to_send() const;
519 
520   void set_ws_key(const StringRef &key);
521 
522   bool get_expect_100_continue() const;
523 
524   bool get_stop_reading() const;
525   void set_stop_reading(bool f);
526 
527   enum {
528     EVENT_ERROR = 0x1,
529     EVENT_TIMEOUT = 0x2,
530   };
531 
532   Downstream *dlnext, *dlprev;
533 
534   // the length of response body sent to upstream client
535   int64_t response_sent_body_length;
536 
537 private:
538   BlockAllocator balloc_;
539 
540   std::vector<nghttp2_rcbuf *> rcbufs_;
541 #ifdef ENABLE_HTTP3
542   std::vector<nghttp3_rcbuf *> rcbufs3_;
543 #endif // ENABLE_HTTP3
544 
545   Request req_;
546   Response resp_;
547 
548   std::chrono::high_resolution_clock::time_point request_start_time_;
549 
550   // host we requested to downstream.  This is used to rewrite
551   // location header field to decide the location should be rewritten
552   // or not.
553   StringRef request_downstream_host_;
554 
555   // Data arrived in frontend before sending header fields to backend
556   // are stored in this buffer.
557   DefaultMemchunks blocked_request_buf_;
558   DefaultMemchunks request_buf_;
559   DefaultMemchunks response_buf_;
560 
561   // The Sec-WebSocket-Key field sent to the peer.  This field is used
562   // if frontend uses RFC 8441 WebSocket bootstrapping via HTTP/2.
563   StringRef ws_key_;
564 
565   ev_timer upstream_rtimer_;
566   ev_timer upstream_wtimer_;
567 
568   ev_timer downstream_rtimer_;
569   ev_timer downstream_wtimer_;
570 
571   Upstream *upstream_;
572   std::unique_ptr<DownstreamConnection> dconn_;
573 
574   // only used by HTTP/2 upstream
575   BlockedLink *blocked_link_;
576   // The backend address used to fulfill this request.  These are for
577   // logging purpose.
578   std::shared_ptr<DownstreamAddrGroup> group_;
579   const DownstreamAddr *addr_;
580   // How many times we tried in backend connection
581   size_t num_retry_;
582   // The stream ID in frontend connection
583   int64_t stream_id_;
584   // The associated stream ID in frontend connection if this is pushed
585   // stream.
586   int64_t assoc_stream_id_;
587   // stream ID in backend connection
588   int64_t downstream_stream_id_;
589   // RST_STREAM error_code from downstream HTTP2 connection
590   uint32_t response_rst_stream_error_code_;
591   // An affinity cookie value.
592   uint32_t affinity_cookie_;
593   // request state
594   DownstreamState request_state_;
595   // response state
596   DownstreamState response_state_;
597   // only used by HTTP/2 upstream
598   DispatchState dispatch_state_;
599   // true if the connection is upgraded (HTTP Upgrade or CONNECT),
600   // excluding upgrade to HTTP/2.
601   bool upgraded_;
602   // true if backend request uses chunked transfer-encoding
603   bool chunked_request_;
604   // true if response to client uses chunked transfer-encoding
605   bool chunked_response_;
606   // true if we have not got final response code
607   bool expect_final_response_;
608   // true if downstream request is pending because backend connection
609   // has not been established or should be checked before use;
610   // currently used only with HTTP/2 connection.
611   bool request_pending_;
612   // true if downstream request header is considered to be sent.
613   bool request_header_sent_;
614   // true if access.log has been written.
615   bool accesslog_written_;
616   // true if affinity cookie is generated for this request.
617   bool new_affinity_cookie_;
618   // true if eof is received from client before sending header fields
619   // to backend.
620   bool blocked_request_data_eof_;
621   // true if request contains "expect: 100-continue" header field.
622   bool expect_100_continue_;
623   bool stop_reading_;
624 };
625 
626 } // namespace shrpx
627 
628 #endif // SHRPX_DOWNSTREAM_H
629