void Client::close() { // Is this an active socket connection? if (isConnected()) { // First, disable sends and receives on this socket. Notify the // other side of the connection that we are going away. int result = ::shutdown(m_socket, SHUT_RDWR); if (-1 == result) { CLIENT_ERROR("failed to shutdown socket communication"); CLIENT_ERROR_OP(return); } #if defined(_WIN32) result = ::closesocket(m_socket); #else result = ::close(m_socket); #endif // _WIN32 if (-1 == result) { CLIENT_ERROR("failed to close socket connection"); CLIENT_ERROR_OP(return); }
void http_client_fiber_main(void) { struct http_client_context *ctx = (struct http_client_context *)current_ctx->reserved; int fd = current_ctx->fd; struct epoll_worker_fd_data *fd_data = epoll_worker_fd_map + fd; TIMEOUT_HANDLER_REMOVE_FD_DATA(fd_data); int persistent = 0; epoll_worker_set_last_fd(fd); /* needed in the case where epoll_wait never occured */ /* * write request */ int res; for (; (res = vmbuf_write(&ctx->request, fd)) == 0; http_client_yield()); if (0 > res) { LOGGER_PERROR("write"); CLIENT_ERROR(); } /* * HTTP header */ uint32_t eoh_ofs; char *data; char *eoh; res = vmbuf_read(&ctx->response, fd); *vmbuf_wloc(&ctx->response) = 0; READ_MORE_DATA_STR(NULL == (eoh = strstr(data = vmbuf_data(&ctx->response), CRLFCRLF))); eoh_ofs = eoh - data + SSTRLEN(CRLFCRLF); *eoh = 0; char *p = strstr(data, CONNECTION); if (p != NULL) { p += SSTRLEN(CONNECTION); persistent = (0 == SSTRNCMPI(CONNECTION_CLOSE, p) ? 0 : 1); } SSTRL(HTTP, "HTTP/"); if (0 != SSTRNCMP(HTTP, data)) CLIENT_ERROR(); p = strchrnul(data, ' '); int code = (*p ? atoi(p + 1) : 0); if (0 == code) CLIENT_ERROR(); do { if (code == 204 || code == 304) /* No Content, Not Modified */ break; /* * content length */ char *content_len_str = strstr(data, CONTENT_LENGTH); if (NULL != content_len_str) { content_len_str += SSTRLEN(CONTENT_LENGTH); size_t content_end = eoh_ofs + atoi(content_len_str); READ_MORE_DATA(vmbuf_wlocpos(&ctx->response) < content_end); break; } /* * chunked encoding */ char *transfer_encoding_str = strstr(data, TRANSFER_ENCODING); if (NULL != transfer_encoding_str && 0 == SSTRNCMP(transfer_encoding_str + SSTRLEN(TRANSFER_ENCODING), "chunked")) { size_t chunk_start = eoh_ofs; size_t data_start = eoh_ofs; char *p; for (;;) { READ_MORE_DATA_STR(*(p = strchrnul((data = vmbuf_data(&ctx->response)) + chunk_start, '\r')) == 0); if (0 != SSTRNCMP(CRLF, p)) CLIENT_ERROR(); uint32_t s = strtoul(data + chunk_start, NULL, 16); if (0 == s) { vmbuf_wlocset(&ctx->response, data_start); break; } chunk_start = p - data + SSTRLEN(CRLF); size_t chunk_end = chunk_start + s + SSTRLEN(CRLF); READ_MORE_DATA(vmbuf_wlocpos(&ctx->response) < chunk_end); memmove(vmbuf_data(&ctx->response) + data_start, vmbuf_data(&ctx->response) + chunk_start, s); data_start += s; chunk_start = chunk_end; } break; } /* * older versions of HTTP, terminated by disconnect */ for (;; yield()) { if ((res = vmbuf_read(&ctx->response, fd)) < 0) CLIENT_ERROR(); if (0 == res) break; /* remote side closed connection */ } } while (0); ctx->content = vmbuf_data_ofs(&ctx->response, eoh_ofs); ctx->content_length = vmbuf_wlocpos(&ctx->response) - eoh_ofs; ctx->http_status_code = code; vmbuf_data_ofs(&ctx->response, eoh_ofs - SSTRLEN(CRLFCRLF))[0] = CR; *vmbuf_wloc(&ctx->response) = 0; ctx->persistent = persistent; if (!persistent) close(fd); }