void PionScheduler::processServiceWork(boost::asio::io_service& service) { while (m_is_running) { try { service.run(); } catch (std::exception& e) { PION_LOG_ERROR(m_logger, e.what()); } catch (...) { PION_LOG_ERROR(m_logger, "caught unrecognized exception"); } } }
void parser::parse_spdy_goaway_frame(boost::system::error_code &ec, const spdy_control_frame_info& frame) { // First complete the check for size // The length should be 4 always if(frame.length != 4){ return; } boost::uint32_t last_good_stream_id = 0; boost::uint32_t status_code = 0; // Get the 31 bit stream id boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); last_good_stream_id = four_bytes & 0x7FFFFFFF; m_read_ptr += 4; // Get the status code status_code = algorithm::to_uint32(m_read_ptr); // Chek if there was an error if(status_code == 1){ PION_LOG_ERROR(m_logger, "There was a Protocol Error"); set_error(ec, ERROR_PROTOCOL_ERROR); return; }else if (status_code == 11) { PION_LOG_ERROR(m_logger, "There was an Internal Error"); set_error(ec, ERROR_INTERNAL_SPDY_ERROR); return; } PION_LOG_INFO(m_logger, "SPDY " << "Status Code is : " << status_code); }
/** * public function to process a new Event. checks to make sure the reactor * is running, increments "events in" counter, and ensures configuration * data is not being changed before calling the virtual process() function * * @param e pointer to the Event to process */ inline void operator()(const EventPtr& e) { if ( isRunning() ) { ConfigReadLock cfg_lock(*this); // re-check after locking if ( isRunning() ) { ++m_events_in; try { process(e); } catch (std::exception& e) { PION_LOG_ERROR(m_logger, "reactor_id: " << getId() << " - " << e.what() << " - rethrowing"); throw; } } } }
void TransformReactor::process(const EventPtr& e) { EventPtr new_e; // Create new event; either same type (if UNDEFINED) or defined type m_event_factory.create(new_e, m_event_type == Vocabulary::UNDEFINED_TERM_REF ? e->getType() : m_event_type); // Copy terms over from original switch (m_copy_original) { case COPY_ALL: // Copy all terms over from original event *new_e += *e; break; case COPY_UNCHANGED: // Copy ONLY terms, that are not defined in transformations... *new_e += *e; // First copy all terms... // Then remove all the ones with transformations... for (TransformChain::iterator i = m_transforms.begin(); i != m_transforms.end(); i++) (*i)->removeTerm(new_e); // TODO: Which is more efficient? Only copying the ones that are not transformed, or this? break; case COPY_NONE: // Do not copy terms from original event break; } try { for (TransformChain::iterator i = m_transforms.begin(); i != m_transforms.end(); i++) (*i)->transform(new_e, e); // transform d <- s } catch (std::exception& e) { // Likely Boost.regex throw PION_LOG_ERROR(m_logger, "reactor_id: " << getId() << " - " << e.what() << " - handled"); } deliverEvent(new_e); // Deliver the modified event // Transformation is done, deliver original event? if (m_deliver_original != DO_NEVER) deliverEvent(e); }
void parser::parse_header_payload(boost::system::error_code &ec, decompressor_ptr& decompressor, const spdy_control_frame_info& frame, http_protocol_info& http_info, boost::uint32_t current_stream_count) { boost::uint32_t stream_id = 0; boost::uint32_t associated_stream_id; boost::uint32_t header_block_length = frame.length; // Get the 31 bit stream id boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); stream_id = four_bytes & 0x7FFFFFFF; m_read_ptr += 4; http_info.stream_id = stream_id; // Get SYN_STREAM-only fields. if (frame.type == SPDY_SYN_STREAM) { // Get associated stream ID. boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); associated_stream_id = four_bytes & 0x7FFFFFFF; m_read_ptr += 4; // The next bits are priority, unused, and slot. // Disregard these for now as we dont need them m_read_ptr +=2 ; } else if( frame.type == SPDY_SYN_REPLY || frame.type == SPDY_HEADERS ) { // Unused bits m_read_ptr +=2 ; } // Get our header block length. switch (frame.type) { case SPDY_SYN_STREAM: header_block_length -= 10; break; case SPDY_SYN_REPLY: case SPDY_HEADERS: // This is a very important distinction. // It should be 6 bytes for SPDYv2 and 4 bytes for SPDYv3. header_block_length -= 6; break; default: // Unhandled case. This should never happen. PION_LOG_ERROR(m_logger, "Invalid SPDY Frame Type"); set_error(ec, ERROR_INVALID_SPDY_FRAME); return; } // Decompress header block as necessary. m_uncompressed_ptr = decompressor->decompress(m_read_ptr, stream_id, frame, header_block_length); if (!m_uncompressed_ptr) { set_error(ec, ERROR_DECOMPRESSION); return; } // Now parse the name/value pairs // The number of name/value pairs is 16 bit SPDYv2 // and it is 32 bit in SPDYv3 // TBD : Add support for SPDYv3 boost::uint16_t num_name_val_pairs = algorithm::to_uint16(m_uncompressed_ptr); m_uncompressed_ptr += 2; std::string content_type = ""; std::string content_encoding = ""; for(boost::uint16_t count = 0; count < num_name_val_pairs; ++count){ // Get the length of the name boost::uint16_t length_name = algorithm::to_uint16(m_uncompressed_ptr); std::string name = ""; m_uncompressed_ptr += 2; { for(boost::uint16_t count = 0; count < length_name; ++count){ name.push_back(*(m_uncompressed_ptr+count)); } m_uncompressed_ptr += length_name; } // Get the length of the value boost::uint16_t length_value = algorithm::to_uint16(m_uncompressed_ptr); std::string value = ""; m_uncompressed_ptr += 2; { for(boost::uint16_t count = 0; count < length_value; ++count){ value.push_back(*(m_uncompressed_ptr+count)); } m_uncompressed_ptr += length_value; } // Save these headers http_info.http_headers.insert(std::make_pair(name, value)); } }
bool parser::populate_frame(boost::system::error_code& ec, spdy_control_frame_info& frame, boost::uint32_t& length_packet, boost::uint32_t& stream_id, http_protocol_info& http_info) { // Get the control bit boost::uint8_t control_bit; boost::uint16_t byte_value = algorithm::to_uint16(m_read_ptr); control_bit = byte_value >> (sizeof(short) * CHAR_BIT - 1); frame.control_bit = (control_bit != 0); if(control_bit){ // Control bit is set; This is a control frame // Get the version number boost::uint16_t two_bytes = algorithm::to_uint16(m_read_ptr); frame.version = two_bytes & 0x7FFF; // Increment the read pointer m_read_ptr += 2; length_packet -= 2; http_info.data_offset +=2; // Get the type frame.type = algorithm::to_uint16(m_read_ptr); if (frame.type >= SPDY_INVALID) { // SPDY Frame is invalid // This is not a SPDY frame, throw an error PION_LOG_ERROR(m_logger, "Invalid SPDY Frame"); set_error(ec, ERROR_INVALID_SPDY_FRAME); return false; } }else { // Control bit is not set; This is a data frame frame.type = SPDY_DATA; frame.version = 0; /* Version doesn't apply to DATA. */ // Get the stream id boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); stream_id = four_bytes & 0x7FFFFFFF; http_info.stream_id = stream_id; m_read_ptr +=2; http_info.data_offset +=2; length_packet -= 2; } // Increment the read pointer m_read_ptr += 2; length_packet -= 2; http_info.data_offset +=2; // Get the flags frame.flags = (boost::uint8_t)*m_read_ptr; // Increment the read pointer // Get the length boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); frame.length = four_bytes & 0xFFFFFF; // Increment the read pointer m_read_ptr += 4; length_packet -= 4; http_info.data_offset +=4; http_info.data_size = frame.length; if(control_bit){ four_bytes = algorithm::to_uint32(m_read_ptr); stream_id = four_bytes & 0x7FFFFFFF; } return true; }
boost::tribool parser::parse_spdy_frame(boost::system::error_code& ec, decompressor_ptr& decompressor, http_protocol_info& http_info, boost::uint32_t& length_packet, boost::uint32_t current_stream_count) { boost::tribool rc = true; // Verify that this is a spdy frame BOOST_ASSERT(m_read_ptr); boost::uint8_t first_byte = (boost::uint8_t)*m_read_ptr; if (first_byte != 0x80 && first_byte != 0x0) { // This is not a SPDY frame, throw an error PION_LOG_ERROR(m_logger, "Invalid SPDY Frame"); set_error(ec, ERROR_INVALID_SPDY_FRAME); return false; } boost::uint8_t control_bit; spdy_control_frame_info frame; boost::uint32_t stream_id = 0; ec.clear(); // Populate the frame bool populate_frame_result = populate_frame(ec, frame, length_packet, stream_id, http_info); if(!populate_frame_result){ /// There was an error; No need to further parse. return false; } BOOST_ASSERT(stream_id != 0); control_bit = (boost::uint8_t)frame.control_bit; // There is a possibility that there are more than one SPDY frames in one TCP frame if(length_packet > frame.length){ m_current_data_chunk_ptr = m_read_ptr + frame.length; length_packet -= frame.length; rc = boost::indeterminate; } if (!control_bit) { // Parse the data packet parse_spdy_data(ec, frame, stream_id, http_info); } /* Abort here if the version is too low. */ if (frame.version > MIN_SPDY_VERSION) { // Version less that min SPDY version, throw an error PION_LOG_ERROR(m_logger, "Invalid SPDY Version Number"); set_error(ec, ERROR_INVALID_SPDY_VERSION); return false; } if(frame.type == SPDY_SYN_STREAM){ http_info.http_type = HTTP_REQUEST; }else if (frame.type == SPDY_SYN_REPLY){ http_info.http_type = HTTP_RESPONSE; }else if (frame.type == SPDY_DATA){ http_info.http_type = HTTP_DATA; } switch (frame.type) { case SPDY_SYN_STREAM: case SPDY_SYN_REPLY: case SPDY_HEADERS: parse_header_payload(ec, decompressor, frame, http_info, current_stream_count); break; case SPDY_RST_STREAM: parse_spdy_rst_stream(ec, frame); http_info.http_type = SPDY_CONTROL; break; case SPDY_SETTINGS: parse_spdy_settings_frame(ec, frame); http_info.http_type = SPDY_CONTROL; break; case SPDY_PING: parse_spdy_ping_frame(ec, frame); http_info.http_type = SPDY_CONTROL; break; case SPDY_GOAWAY: parse_spdy_goaway_frame(ec, frame); http_info.http_type = SPDY_CONTROL; break; case SPDY_WINDOW_UPDATE: parse_spdy_window_update_frame(ec, frame); http_info.http_type = SPDY_CONTROL; break; case SPDY_CREDENTIAL: // We dont need to parse this for now http_info.http_type = SPDY_CONTROL; break; default: break; } if (ec) return false; m_last_data_chunk_ptr = m_read_ptr; m_read_ptr = m_current_data_chunk_ptr; return rc; }
void HTTPServer::handleRequest(HTTPRequestPtr& http_request, TCPConnectionPtr& tcp_conn) { if (! http_request->isValid()) { // the request is invalid or an error occured PION_LOG_INFO(m_logger, "Received an invalid HTTP request"); m_bad_request_handler(http_request, tcp_conn); return; } PION_LOG_DEBUG(m_logger, "Received a valid HTTP request"); // strip off trailing slash if the request has one std::string resource_requested(stripTrailingSlash(http_request->getResource())); // apply any redirection RedirectMap::const_iterator it = m_redirects.find(resource_requested); unsigned int num_redirects = 0; while (it != m_redirects.end()) { if (++num_redirects > MAX_REDIRECTS) { PION_LOG_ERROR(m_logger, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource: " << http_request->getOriginalResource()); m_server_error_handler(http_request, tcp_conn, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource"); return; } resource_requested = it->second; http_request->changeResource(resource_requested); it = m_redirects.find(resource_requested); } // if authentication activated, check current request if (m_auth) { // try to verify authentication if (! m_auth->handleRequest(http_request, tcp_conn)) { // the HTTP 401 message has already been sent by the authentication object PION_LOG_DEBUG(m_logger, "Authentication required for HTTP resource: " << resource_requested); if (http_request->getResource() != http_request->getOriginalResource()) { PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource()); } return; } } // search for a handler matching the resource requested RequestHandler request_handler; if (findRequestHandler(resource_requested, request_handler)) { // try to handle the request try { request_handler(http_request, tcp_conn); PION_LOG_DEBUG(m_logger, "Found request handler for HTTP resource: " << resource_requested); if (http_request->getResource() != http_request->getOriginalResource()) { PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource()); } } catch (HTTPResponseWriter::LostConnectionException& e) { // the connection was lost while or before sending the response PION_LOG_WARN(m_logger, "HTTP request handler: " << e.what()); tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE); // make sure it will get closed tcp_conn->finish(); } catch (std::bad_alloc&) { // propagate memory errors (FATAL) throw; } catch (std::exception& e) { // recover gracefully from other exceptions thrown request handlers PION_LOG_ERROR(m_logger, "HTTP request handler: " << e.what()); m_server_error_handler(http_request, tcp_conn, e.what()); } } else { // no web services found that could handle the request PION_LOG_INFO(m_logger, "No HTTP request handlers found for resource: " << resource_requested); if (http_request->getResource() != http_request->getOriginalResource()) { PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource()); } m_not_found_handler(http_request, tcp_conn); } }