Commit 7db586d8 authored by Yann Garcia's avatar Yann Garcia
Browse files

Fixing bug linked to HTTP header Connection: Close

parent 0cf0296b
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -109,13 +109,28 @@ public: //! \publicsection
   * \todo Remove the logs
   * \virtual
   */
  virtual void receive_data(OCTETSTRING &p_data, params &p_params) {}
  virtual void receive_data(OCTETSTRING &p_data, params &p_params) {};

  /*!
   * \virtual
   * \fn void close_connection();
   * \brief Request the transport layer(s) below to close the current
   *        connection (e.g. after an HTTP "Connection: close" header).
   *        The next send_data() on the transport layer re-establishes it.
   */
  virtual void close_connection() {
    printf(">>> close_connection: lowerLayers size=%d\n", (int)lowerLayers.size());
    for (std::vector<layer *>::const_iterator it = lowerLayers.cbegin(); it != lowerLayers.cend(); ++it) {
      (*it)->close_connection();
    }
    printf("<<< close_connection\n");
  };

  /*!
   * \inline
   * \fn const std::string& to_string();
   * \brief Remove the specified upper layer protocol from the list of the upper layer
   * \param[in] The layer protocol to be removed
   * \brief Return the string representation of the layer
   * \return The string representation of the layer
   */
  inline const std::string& to_string() const { return type; };

@@ -144,3 +159,4 @@ protected: //! \protectedsection
    } // End of 'for' statement
  };
}; // End of class layer
+24 −1
Original line number Diff line number Diff line
@@ -220,8 +220,31 @@ void http_layer::receive_data(OCTETSTRING &p_data, params &params) {
    return;
  }

  // "Connection: close" in a response means the server will close this connection after the response. 
  // Tear the TCP connection down now so the next request is sent on a fresh connection instead of being RST by the server (see RFC 9112 §9.6).
  if (http_message.ischosen(LibHttp__TypesAndValues::HttpMessage::ALT_response)) {
    for (int i = 0; i < http_message.response().header().lengthof(); i++) {
      const CHARSTRING& hname = http_message.response().header()[i].header__name();
      if (strcasecmp(static_cast<const char*>(hname), "Connection") != 0) {
        continue;
      }
      const OPTIONAL<LibHttp__TypesAndValues::charstring__list> &o = http_message.response().header()[i].header__value();
      if (!o.ispresent()) {
        continue;
      }
      const LibHttp__TypesAndValues::charstring__list &v = dynamic_cast<const OPTIONAL<LibHttp__TypesAndValues::charstring__list> &>(o);
      for (int j = 0; j < v.lengthof(); j++) {
        if (strcasestr(static_cast<const char*>(v[j]), "close") != nullptr) {
          loggers::get_instance().log("http_layer::receive_data: 'Connection: close' received, closing transport connection");
          close_connection(); // Propagates down to tcp_layer
          break;
        }
      } // End of 'for' statement
    } // End of 'for' statement
  }

  loggers::get_instance().log("http_layer::receive_data: Device mode: %d", _device_mode);
  if (_device_mode) {
    loggers::get_instance().log("http_layer::receive_data: Device mode set");
    OCTETSTRING os(0, nullptr);
    if (http_message.ischosen(LibHttp__TypesAndValues::HttpMessage::ALT_response)) {
      if (http_message.response().body().ispresent()) {
+21 −0
Original line number Diff line number Diff line
@@ -286,5 +286,26 @@ void tcp_layer::peer_disconnected(int p_client_id)
	_client_id = -1;
}

void tcp_layer::peer_half_closed(int p_client_id)
{
  loggers::get_instance().log(">>> tcp_layer::peer_half_closed: %d", p_client_id);

  // The server sent a FIN (e.g. after "Connection: close"): the connection
  // cannot carry a new request. Drop it from the peer list so that
  // send_data() re-establishes a fresh connection on the next request.
  remove_client(p_client_id);
  peer_disconnected(p_client_id);
}

void tcp_layer::close_connection()
{
  loggers::get_instance().log(">>> tcp_layer::close_connection: _client_id: %d", _client_id);

  if ((_params[params::server_mode].compare("0") == 0) && (_client_id != -1)) {
    remove_client(_client_id);
    _client_id = -1;
  }
}

tcp_layer_factory tcp_layer_factory::_f;
+6 −0
Original line number Diff line number Diff line
@@ -67,6 +67,11 @@ public: //! \publicsection
   */
  virtual void receive_data(OCTETSTRING &p_data, params &info);

  /*! 
   * \brief Close the active client connection so the next send_data() reconnects. 
   */
  virtual void close_connection();

  /*!
   * \virtual
   * \fn void message_incoming(const uint8_t* message_buffer, int length, int client_id = -1);
@@ -101,6 +106,7 @@ protected: //! \protectedsection
  int  send_message_on_nonblocking_fd(int client_id, const uint8_t *message_buffer, int length_of_message);
  int  receive_message_on_fd(int p_client_id);
  void peer_disconnected(int p_client_id);
  void peer_half_closed(int p_client_id);

private: //! \privatesection
  void Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable, boolean is_error);