System_http_session::System_http_session(Move<Unique_file> socket, boost::shared_ptr<const Http::Authentication_context> auth_ctx) : Http::Session(STD_MOVE(socket)) , m_auth_ctx(STD_MOVE(auth_ctx)) , m_initialized(false), m_decoded_uri(), m_servlet() { POSEIDON_LOG_INFO("System_http_session constructor: remote = ", get_remote_info()); }
void System_http_session::on_sync_request(Http::Request_headers request_headers, Stream_buffer request_entity){ POSEIDON_PROFILE_ME; initialize_once(request_headers); const bool keep_alive = Http::is_keep_alive_enabled(request_headers); Http::Response_headers response_headers; response_headers.version = 10001; response_headers.status_code = Http::status_ok; response_headers.reason = "OK"; response_headers.headers.set(Rcnts::view("Connection"), keep_alive ? "Keep-Alive" : "Close"); response_headers.headers.set(Rcnts::view("Access-Control-Allow-Origin"), "*"); response_headers.headers.set(Rcnts::view("Access-Control-Allow-Headers"), "Authorization, Content-Type"); response_headers.headers.set(Rcnts::view("Access-Control-Allow-Methods"), "OPTIONS, GET, HEAD, POST"); Json_object request; Buffer_istream bis; Json_object response; Buffer_ostream bos; switch(request_headers.verb){ case Http::verb_options: Http::Session::send(STD_MOVE(response_headers)); break; case Http::verb_get: case Http::verb_head: case Http::verb_post: POSEIDON_THROW_ASSERT(m_servlet); if(request_headers.verb != Http::verb_post){ // no parameters } else { POSEIDON_LOG_DEBUG("Parsing POST entity as JSON Object: ", request_entity); bis.set_buffer(STD_MOVE(request_entity)); request.parse(bis); POSEIDON_THROW_UNLESS(bis, Http::Exception, Http::status_bad_request); } POSEIDON_LOG_DEBUG("System_http_session request: ", request); if(request_headers.verb != Http::verb_post){ m_servlet->handle_get(response); } else { m_servlet->handle_post(response, STD_MOVE(request)); } POSEIDON_LOG_DEBUG("System_http_session response: ", response); response.dump(bos); response_headers.headers.set(Rcnts::view("Content-Type"), "application/json"); Http::Session::send_chunked_header(STD_MOVE(response_headers)); if(request_headers.verb == Http::verb_head){ POSEIDON_LOG_DEBUG("The response entity for a HEAD request will be discarded."); break; } Http::Session::send_chunk(STD_MOVE(bos.get_buffer())); Http::Session::send_chunked_trailer(); break; default: POSEIDON_THROW(Http::Exception, Http::status_method_not_allowed); } }
void TcpClientBase::realConnect(bool useSsl){ if(::connect(m_socket.get(), static_cast<const ::sockaddr *>(SockAddr::getData()), SockAddr::getSize()) != 0){ if(errno != EINPROGRESS){ DEBUG_THROW(SystemException); } } if(useSsl){ LOG_POSEIDON_INFO("Initiating SSL handshake..."); AUTO(ssl, g_clientSslFactory.createSsl()); boost::scoped_ptr<SslFilterBase> filter(new SslFilter(STD_MOVE(ssl), getFd())); initSsl(STD_MOVE(filter)); } }
boost::shared_ptr<const JobPromise> DnsDaemon::enqueue_for_looking_up(boost::shared_ptr<SockAddr> sock_addr, std::string host, unsigned port){ PROFILE_ME; AUTO(promise, boost::make_shared<JobPromise>()); const AUTO(param, new DnsCallbackParam(STD_MOVE(sock_addr), host, port, promise)); atomic_add(g_pending_callback_count, 1, ATOMIC_RELAXED); // noexcept try { ::sigevent sev; sev.sigev_notify = SIGEV_THREAD; sev.sigev_value.sival_ptr = param; sev.sigev_notify_function = &dns_callback; sev.sigev_notify_attributes = NULLPTR; AUTO(pcb, &(param->cb)); const int gai_code = ::getaddrinfo_a(GAI_NOWAIT, &pcb, 1, &sev); // noexcept if(gai_code != 0){ LOG_POSEIDON_WARNING("DNS failure: gai_code = ", gai_code, ", err_msg = ", ::gai_strerror(gai_code)); DEBUG_THROW(Exception, sslit("DNS failure")); } } catch(...){ atomic_sub(g_pending_callback_count, 1, ATOMIC_RELAXED); // noexcept delete param; throw; } return promise; }
void System_http_session::on_sync_expect(Http::Request_headers request_headers){ POSEIDON_PROFILE_ME; initialize_once(request_headers); Http::Session::on_sync_expect(STD_MOVE(request_headers)); }
long ClientWriter::put_request_headers(RequestHeaders request_headers){ PROFILE_ME; StreamBuffer data; data.put(get_string_from_verb(request_headers.verb)); data.put(' '); data.put(request_headers.uri); if(!request_headers.get_params.empty()){ data.put('?'); data.put(url_encoded_from_optional_map(request_headers.get_params)); } char temp[64]; const unsigned ver_major = request_headers.version / 10000, ver_minor = request_headers.version % 10000; unsigned len = (unsigned)std::sprintf(temp, " HTTP/%u.%u\r\n", ver_major, ver_minor); data.put(temp, len); AUTO_REF(headers, request_headers.headers); for(AUTO(it, headers.begin()); it != headers.end(); ++it){ data.put(it->first.get()); data.put(": "); data.put(it->second); data.put("\r\n"); } data.put("\r\n"); return on_encoded_data_avail(STD_MOVE(data)); }
SslFilterBase::SslFilterBase(Move<UniqueSsl> ssl, int fd) : m_ssl(STD_MOVE(ssl)), m_fd(fd) , m_established(false) { if(!::SSL_set_fd(m_ssl.get(), fd)){ DEBUG_THROW(Exception, sslit("::SSL_set_fd() failed")); } }
int file_put_contents_nothrow(const char *path, StreamBuffer contents, bool append){ try { file_put_contents(path, STD_MOVE(contents), append); return 0; } catch(SystemException &e){ return e.code(); } }
long ClientWriter::put_chunked_header(RequestHeaders request_headers){ PROFILE_ME; StreamBuffer data; data.put(get_string_from_verb(request_headers.verb)); data.put(' '); data.put(request_headers.uri); if(!request_headers.get_params.empty()){ data.put('?'); data.put(url_encoded_from_optional_map(request_headers.get_params)); } char temp[64]; const unsigned ver_major = request_headers.version / 10000, ver_minor = request_headers.version % 10000; unsigned len = (unsigned)std::sprintf(temp, " HTTP/%u.%u\r\n", ver_major, ver_minor); data.put(temp, len); AUTO_REF(headers, request_headers.headers); if(!headers.has("Content-Type")){ headers.set(sslit("Content-Type"), "application/x-www-form-urlencoded; charset=utf-8"); } AUTO(transfer_encoding, headers.get("Transfer-Encoding")); AUTO(pos, transfer_encoding.find(';')); if(pos != std::string::npos){ transfer_encoding.erase(pos); } transfer_encoding = to_lower_case(trim(STD_MOVE(transfer_encoding))); if(transfer_encoding.empty() || (transfer_encoding == STR_IDENTITY)){ headers.set(sslit("Transfer-Encoding"), STR_CHUNKED); } else { headers.set(sslit("Transfer-Encoding"), STD_MOVE(transfer_encoding)); } for(AUTO(it, headers.begin()); it != headers.end(); ++it){ data.put(it->first.get()); data.put(": "); data.put(it->second); data.put("\r\n"); } data.put("\r\n"); return on_encoded_data_avail(STD_MOVE(data)); }
bool TcpServerBase::poll() const { UniqueFile client(::accept(get_fd(), NULLPTR, NULLPTR)); if(!client){ if(errno != EAGAIN){ DEBUG_THROW(SystemException); } return false; } AUTO(session, on_client_connect(STD_MOVE(client))); if(!session){ LOG_POSEIDON_WARNING("on_client_connect() returns a null pointer."); DEBUG_THROW(Exception, sslit("Null client pointer")); } if(m_ssl_factory){ AUTO(ssl, m_ssl_factory->create_ssl()); boost::scoped_ptr<SslFilterBase> filter(new SslFilter(STD_MOVE(ssl), session->get_fd())); session->init_ssl(STD_MOVE(filter)); } session->set_timeout(EpollDaemon::get_tcp_request_timeout()); EpollDaemon::add_session(session); LOG_POSEIDON_INFO("Accepted TCP connection from ", session->get_remote_info()); return true; }
long ClientWriter::put_chunked_trailer(OptionalMap headers){ PROFILE_ME; StreamBuffer data; data.put("0\r\n"); for(AUTO(it, headers.begin()); it != headers.end(); ++it){ data.put(it->first.get()); data.put(": "); data.put(it->second); data.put("\r\n"); } data.put("\r\n"); return on_encoded_data_avail(STD_MOVE(data)); }
SocketServerBase::SocketServerBase(UniqueFile socket) : m_socket(STD_MOVE(socket)), m_local_info(get_local_ip_port_from_fd(m_socket.get())) { const int flags = ::fcntl(m_socket.get(), F_GETFL); if(flags == -1){ const int code = errno; LOG_POSEIDON_ERROR("Could not get fcntl flags on socket."); DEBUG_THROW(SystemException, code); } if(::fcntl(m_socket.get(), F_SETFL, flags | O_NONBLOCK) != 0){ const int code = errno; LOG_POSEIDON_ERROR("Could not set fcntl flags on socket."); DEBUG_THROW(SystemException, code); } LOG_POSEIDON_INFO("Created socket server, local = ", m_local_info); }
long ClientWriter::put_chunk(StreamBuffer entity){ PROFILE_ME; if(entity.empty()){ LOG_POSEIDON_ERROR("You are not allowed to send an empty chunk"); DEBUG_THROW(BasicException, sslit("You are not allowed to send an empty chunk")); } StreamBuffer chunk; char temp[64]; unsigned len = (unsigned)std::sprintf(temp, "%llx\r\n", (unsigned long long)entity.size()); chunk.put(temp, len); chunk.splice(entity); chunk.put("\r\n"); return on_encoded_data_avail(STD_MOVE(chunk)); }
bool LowLevelClient::send_chunked_trailer(OptionalMap headers){ PROFILE_ME; return ClientWriter::put_chunked_trailer(STD_MOVE(headers)); }
bool LowLevelClient::send_chunk(StreamBuffer entity){ PROFILE_ME; return ClientWriter::put_chunk(STD_MOVE(entity)); }
bool LowLevelClient::send_chunked_header(RequestHeaders request_headers){ PROFILE_ME; return ClientWriter::put_chunked_header(STD_MOVE(request_headers)); }
bool LowLevelClient::send(RequestHeaders request_headers, StreamBuffer entity){ PROFILE_ME; return ClientWriter::put_request(STD_MOVE(request_headers), STD_MOVE(entity)); }
bool LowLevelClient::send_entity(StreamBuffer data){ PROFILE_ME; return ClientWriter::put_entity(STD_MOVE(data)); }
long LowLevelClient::on_encoded_data_avail(StreamBuffer encoded){ PROFILE_ME; return TcpClientBase::send(STD_MOVE(encoded)); }
void Ssl_server_factory::create_ssl_filter(boost::scoped_ptr<Ssl_filter> &ssl_filter, int fd){ Unique_ssl ssl; POSEIDON_THROW_UNLESS(ssl.reset(::SSL_new(m_ssl_ctx.get())), Exception, Rcnts::view("::SSL_new() failed")); ssl_filter.reset(new Ssl_filter(STD_MOVE(ssl), Ssl_filter::to_accept, fd)); }
void LowLevelClient::on_response_entity(boost::uint64_t entity_offset, bool is_chunked, StreamBuffer entity){ PROFILE_ME; on_low_level_response_entity(entity_offset, is_chunked, STD_MOVE(entity)); }
ProtocolException(const char *file, std::size_t line, std::string what, int code) : Exception(file, line, STD_MOVE(what)), m_code(code) { }
Exception(const char *file, std::size_t line, std::string what) : std::runtime_error(STD_MOVE(what)), m_file(file), m_line(line) { }
long ClientWriter::put_request(RequestHeaders request_headers, StreamBuffer entity){ PROFILE_ME; StreamBuffer data; data.put(get_string_from_verb(request_headers.verb)); data.put(' '); data.put(request_headers.uri); if(!request_headers.get_params.empty()){ data.put('?'); data.put(url_encoded_from_optional_map(request_headers.get_params)); } char temp[64]; const unsigned ver_major = request_headers.version / 10000, ver_minor = request_headers.version % 10000; unsigned len = (unsigned)std::sprintf(temp, " HTTP/%u.%u\r\n", ver_major, ver_minor); data.put(temp, len); AUTO_REF(headers, request_headers.headers); if(entity.empty()){ headers.erase("Content-Type"); headers.erase("Transfer-Encoding"); if((request_headers.verb == V_POST) || (request_headers.verb == V_PUT)){ headers.set(sslit("Content-Length"), STR_0); } else { headers.erase("Content-Length"); } } else { if(!headers.has("Content-Type")){ headers.set(sslit("Content-Type"), "application/x-www-form-urlencoded; charset=utf-8"); } AUTO(transfer_encoding, headers.get("Transfer-Encoding")); AUTO(pos, transfer_encoding.find(';')); if(pos != std::string::npos){ transfer_encoding.erase(pos); } transfer_encoding = to_lower_case(trim(STD_MOVE(transfer_encoding))); if(transfer_encoding.empty() || (transfer_encoding == STR_IDENTITY)){ headers.set(sslit("Content-Length"), boost::lexical_cast<std::string>(entity.size())); } else { // 只有一个 chunk。 StreamBuffer chunk; len = (unsigned)std::sprintf(temp, "%llx\r\n", (unsigned long long)entity.size()); chunk.put(temp, len); chunk.splice(entity); chunk.put("\r\n0\r\n\r\n"); entity.swap(chunk); } } for(AUTO(it, headers.begin()); it != headers.end(); ++it){ data.put(it->first.get()); data.put(": "); data.put(it->second); data.put("\r\n"); } data.put("\r\n"); data.splice(entity); return on_encoded_data_avail(STD_MOVE(data)); }
SystemSession(UniqueFile socket, boost::shared_ptr<const Http::AuthInfo> authInfo, std::string prefix) : Http::Session(STD_MOVE(socket)) , m_authInfo(STD_MOVE(authInfo)), m_prefix(STD_MOVE(prefix)) { }
void CsvParser::load(const char *file){ LOG_POSEIDON_DEBUG("Loading CSV file: ", file); StreamBuffer buffer; fileGetContents(buffer, file); buffer.put('\n'); std::vector<OptionalMap> data; std::vector<std::vector<std::string> > rows; { std::vector<std::string> row; std::string token; bool first = true; bool inQuote = false; do { char ch = buffer.get(); if(ch == '\r'){ if(buffer.peek() == '\n'){ buffer.get(); } ch = '\n'; } if(first){ first = false; if(ch == '\"'){ inQuote = true; continue; } } if(ch == '\"'){ if(inQuote){ if(buffer.peek() == '\"'){ buffer.get(); token.push_back('\"'); } else { inQuote = false; } continue; } } if(!inQuote){ if((ch == ',') || (ch == '\n')){ std::string trimmed; const std::size_t begin = token.find_first_not_of(" \t\r\n"); if(begin != std::string::npos){ const std::size_t end = token.find_last_not_of(" \t\r\n") + 1; trimmed = token.substr(begin, end - begin); } row.push_back(STD_MOVE(trimmed)); token.clear(); first = true; if(ch == '\n'){ rows.push_back(STD_MOVE(row)); row.clear(); } continue; } } token.push_back(ch); } while(!buffer.empty()); } if(rows.empty() || rows.front().empty()){ LOG_POSEIDON_ERROR("The first line of a CSV file may not be empty."); DEBUG_THROW(Exception, sslit("Bad CSV header")); } const std::size_t columnCount = rows.front().size(); std::vector<SharedNts> keys(columnCount); for(std::size_t i = 0; i < columnCount; ++i){ AUTO_REF(key, rows.front().at(i)); for(std::size_t j = 0; j < i; ++j){ if(keys.at(j) == key){ LOG_POSEIDON_ERROR("Duplicate key: ", key); DEBUG_THROW(Exception, sslit("Duplicate key")); } } keys.at(i).assign(key.c_str()); } for(std::size_t i = 1; i < rows.size(); ++i){ rows.at(i - 1).swap(rows.at(i)); } rows.pop_back(); { std::size_t line = 1; std::size_t i = 0; while(i < rows.size()){ AUTO_REF(row, rows.at(i)); ++line; if((row.size() == 1) && row.front().empty()){ for(std::size_t j = i + 1; j < rows.size(); ++j){ rows.at(j - 1).swap(rows.at(j)); } rows.pop_back(); continue; } if(row.size() != columnCount){ LOG_POSEIDON_ERROR("There are ", row.size(), " column(s) on line ", line, " but there are ", columnCount, " in the header"); DEBUG_THROW(Exception, sslit("Inconsistent CSV column numbers")); } ++i; } } const std::size_t rowCount = rows.size(); data.resize(rowCount); for(std::size_t i = 0; i < rowCount; ++i){ AUTO_REF(row, rows.at(i)); AUTO_REF(map, data.at(i)); for(std::size_t j = 0; j < columnCount; ++j){ map.create(keys.at(j))->second.swap(row.at(j)); } } LOG_POSEIDON_DEBUG("Done loading CSV file: ", file); m_data.swap(data); m_row = static_cast<std::size_t>(-1); }
void EpollDaemon::registerServer(boost::weak_ptr<const SocketServerBase> server){ const Mutex::UniqueLock lock(g_serverMutex); g_servers.push_back(STD_MOVE(server)); }
bool LowLevelClient::on_response_end(boost::uint64_t content_length, bool is_chunked, OptionalMap headers){ PROFILE_ME; return on_low_level_response_end(content_length, is_chunked, STD_MOVE(headers)); }
// SslFactoryBase SslFactoryBase::SslFactoryBase(UniqueSslCtx ssl_ctx) : m_ssl_ctx(STD_MOVE(ssl_ctx)) { }
long ClientWriter::put_entity(StreamBuffer data){ PROFILE_ME; return on_encoded_data_avail(STD_MOVE(data)); }