• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Http2ConnectionState.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   Http2ConnectionState.
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "P_Net.h"
00025 #include "Http2ConnectionState.h"
00026 #include "Http2ClientSession.h"
00027 
00028 #define DebugHttp2Ssn(fmt, ...) \
00029   DebugSsn("http2_cs",  "[%" PRId64 "] " fmt, this->con_id, __VA_ARGS__)
00030 
00031 typedef Http2ErrorCode (*http2_frame_dispatch)(Http2ClientSession&, Http2ConnectionState&, const Http2Frame&);
00032 
00033 static Http2ErrorCode
00034 rcv_settings_frame(Http2ClientSession& cs, Http2ConnectionState& cstate, const Http2Frame& frame)
00035 {
00036   Http2SettingsParameter  param;
00037   char      buf[HTTP2_SETTINGS_PARAMETER_LEN];
00038   unsigned  nbytes = 0;
00039   char *    end;
00040 
00041   // 6.5 The stream identifier for a SETTINGS frame MUST be zero.
00042   if (frame.header().streamid != 0) {
00043     return HTTP2_ERROR_PROTOCOL_ERROR;
00044   }
00045 
00046   // 6.5 Receipt of a SETTINGS frame with the ACK flag set and a
00047   // length field value other than 0 MUST be treated as a connection
00048   // error of type FRAME_SIZE_ERROR.
00049   if (frame.header().flags & HTTP2_FLAGS_SETTINGS_ACK) {
00050     return frame.header().length == 0 ? HTTP2_ERROR_NO_ERROR : HTTP2_ERROR_FRAME_SIZE_ERROR;
00051   }
00052 
00053   while (nbytes < frame.header().length) {
00054     end = frame.reader()->memcpy(buf, sizeof(buf), nbytes);
00055     nbytes += (end - buf);
00056 
00057     if (!http2_parse_settings_parameter(make_iovec(buf, end - buf), param)) {
00058       return HTTP2_ERROR_PROTOCOL_ERROR;
00059     }
00060 
00061     if (!http2_settings_parameter_is_valid(param)) {
00062       return param.id == HTTP2_SETTINGS_INITIAL_WINDOW_SIZE
00063         ? HTTP2_ERROR_FLOW_CONTROL_ERROR : HTTP2_ERROR_PROTOCOL_ERROR;
00064     }
00065 
00066     DebugSsn(&cs, "http2_cs",  "[%" PRId64 "] setting param=%d value=%u",
00067         cs.connection_id(), param.id, param.value);
00068 
00069     cstate.client_settings.set((Http2SettingsIdentifier)param.id, param.value);
00070   }
00071 
00072   return HTTP2_ERROR_NO_ERROR;
00073 }
00074 
00075 static const int buffer_size_index[HTTP2_FRAME_TYPE_MAX] =
00076 {
00077   -1,   // HTTP2_FRAME_TYPE_DATA
00078   -1,   // HTTP2_FRAME_TYPE_HEADERS
00079   -1,   // HTTP2_FRAME_TYPE_PRIORITY
00080   -1,   // HTTP2_FRAME_TYPE_RST_STREAM
00081   -1,   // HTTP2_FRAME_TYPE_SETTINGS
00082   -1,   // HTTP2_FRAME_TYPE_PUSH_PROMISE
00083   -1,   // HTTP2_FRAME_TYPE_PING
00084   BUFFER_SIZE_INDEX_128,   // HTTP2_FRAME_TYPE_GOAWAY
00085   -1,   // HTTP2_FRAME_TYPE_WINDOW_UPDATE
00086   -1,   // HTTP2_FRAME_TYPE_CONTINUATION
00087   -1,   // HTTP2_FRAME_TYPE_ALTSVC
00088   -1,   // HTTP2_FRAME_TYPE_BLOCKED
00089 };
00090 
00091 static const http2_frame_dispatch frame_handlers[HTTP2_FRAME_TYPE_MAX] =
00092 {
00093   NULL,   // HTTP2_FRAME_TYPE_DATA
00094   NULL,   // HTTP2_FRAME_TYPE_HEADERS
00095   NULL,   // HTTP2_FRAME_TYPE_PRIORITY
00096   NULL,   // HTTP2_FRAME_TYPE_RST_STREAM
00097   rcv_settings_frame,   // HTTP2_FRAME_TYPE_SETTINGS
00098   NULL,   // HTTP2_FRAME_TYPE_PUSH_PROMISE
00099   NULL,   // HTTP2_FRAME_TYPE_PING
00100   NULL,   // HTTP2_FRAME_TYPE_GOAWAY
00101   NULL,   // HTTP2_FRAME_TYPE_WINDOW_UPDATE
00102   NULL,   // HTTP2_FRAME_TYPE_CONTINUATION
00103   NULL,   // HTTP2_FRAME_TYPE_ALTSVC
00104   NULL,   // HTTP2_FRAME_TYPE_BLOCKED
00105 };
00106 
00107 int
00108 Http2ConnectionState::main_event_handler(int event, void * edata)
00109 {
00110   if (event == HTTP2_SESSION_EVENT_INIT) {
00111     ink_assert(this->ua_session == NULL);
00112     this->ua_session = (Http2ClientSession *)edata;
00113 
00114     return 0;
00115   }
00116 
00117   if (event == HTTP2_SESSION_EVENT_FINI) {
00118     this->ua_session = NULL;
00119     SET_HANDLER(&Http2ConnectionState::state_closed);
00120     return 0;
00121   }
00122 
00123   if (event == HTTP2_SESSION_EVENT_RECV) {
00124     Http2Frame * frame = (Http2Frame *)edata;
00125     Http2ErrorCode error;
00126 
00127     // The session layer should have validated the frame already.
00128     ink_assert(frame->header().type < countof(frame_handlers));
00129 
00130     if (frame_handlers[frame->header().type]) {
00131       error = frame_handlers[frame->header().type](*this->ua_session, *this, *frame);
00132     } else {
00133       error = HTTP2_ERROR_INTERNAL_ERROR;
00134     }
00135 
00136     if (error != HTTP2_ERROR_NO_ERROR) {
00137       Http2Frame frame(HTTP2_FRAME_TYPE_GOAWAY, 0, 0);
00138       Http2Goaway goaway;
00139 
00140       goaway.last_streamid = 0;
00141       goaway.error_code = error;
00142 
00143       frame.alloc(buffer_size_index[HTTP2_FRAME_TYPE_GOAWAY]);
00144       http2_write_goaway(goaway, frame.write());
00145       frame.finalize(HTTP2_GOAWAY_LEN);
00146 
00147       this->ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &frame);
00148       eventProcessor.schedule_imm(this->ua_session, ET_NET, VC_EVENT_ERROR);
00149 
00150       // XXX We need to think a bit harder about how to coordinate the client session and the
00151       // protocol connection. At this point, the protocol is shutting down, but there's no way
00152       // to tell that to the client session. Perhaps this could be solved by implementing the
00153       // half-closed state ...
00154       SET_HANDLER(&Http2ConnectionState::state_closed);
00155     }
00156 
00157     return 0;
00158   }
00159 
00160   return 0;
00161 }
00162 
00163 int
00164 Http2ConnectionState::state_closed(int /* event */, void * /* edata */)
00165 {
00166   return 0;
00167 }

Generated by  doxygen 1.7.1