// retoor #include "http_response.h" #include "time_utils.h" #include "epoll_utils.h" #include "buffer.h" #include #include #include int http_response_build(const http_response_params_t *params, char *buf, size_t buf_size) { if (!params || !buf || buf_size == 0) return -1; char date_buf[64]; time_format_http_date_now(date_buf, sizeof(date_buf)); const char *content_type = params->content_type ? params->content_type : "text/plain; charset=utf-8"; const char *body = params->body ? params->body : ""; size_t body_len = params->body_len > 0 ? params->body_len : strlen(body); const char *connection = params->keep_alive ? "keep-alive" : "close"; const char *extra = params->extra_headers ? params->extra_headers : ""; int len = snprintf(buf, buf_size, "HTTP/1.1 %d %s\r\n" "Content-Type: %s\r\n" "Content-Length: %zu\r\n" "Connection: %s\r\n" "Date: %s\r\n" "Server: ReverseProxy/4.0\r\n" "%s" "\r\n", params->code, params->status, content_type, body_len, connection, date_buf, extra); if (len < 0 || (size_t)len >= buf_size) return -1; if (body_len > 0 && (size_t)len + body_len < buf_size) { memcpy(buf + len, body, body_len); len += (int)body_len; } return len; } void http_response_send(connection_t *conn, const http_response_params_t *params) { if (!conn || !params) return; char response[ERROR_RESPONSE_SIZE]; int len = http_response_build(params, response, sizeof(response)); if (len <= 0) return; if (buffer_ensure_capacity(&conn->write_buf, conn->write_buf.tail + (size_t)len) == 0) { memcpy(conn->write_buf.data + conn->write_buf.tail, response, (size_t)len); conn->write_buf.tail += (size_t)len; struct epoll_event event = { .data.fd = conn->fd, .events = EPOLLIN | EPOLLOUT }; epoll_ctl(epoll_fd, EPOLL_CTL_MOD, conn->fd, &event); } } void http_response_send_error(connection_t *conn, int code, const char *status, const char *body) { if (!conn || !status || !body) return; http_response_params_t params = { .code = code, .status = status, .body = body, .keep_alive = 0 }; http_response_send(conn, ¶ms); conn->state = CLIENT_STATE_ERROR; conn->request.keep_alive = 0; } void http_response_send_auth_required(connection_t *conn, const char *realm) { if (!conn) return; char extra_headers[256]; snprintf(extra_headers, sizeof(extra_headers), "WWW-Authenticate: Basic realm=\"%s\"\r\n", realm ? realm : "Protected Area"); http_response_params_t params = { .code = 401, .status = "Unauthorized", .body = "401 Unauthorized - Authentication required", .extra_headers = extra_headers, .keep_alive = 0 }; http_response_send(conn, ¶ms); conn->state = CLIENT_STATE_ERROR; conn->request.keep_alive = 0; } void http_response_send_pipeline_rejected(connection_t *conn) { if (!conn) return; http_response_params_t params = { .code = 400, .status = "Bad Request", .body = "400 Bad Request - Request pipelining is not supported", .keep_alive = 0 }; char response[ERROR_RESPONSE_SIZE]; int len = http_response_build(¶ms, response, sizeof(response)); if (len <= 0) return; if (buffer_ensure_capacity(&conn->write_buf, conn->write_buf.tail + (size_t)len) == 0) { memcpy(conn->write_buf.data + conn->write_buf.tail, response, (size_t)len); conn->write_buf.tail += (size_t)len; } conn->state = CLIENT_STATE_CLOSING; conn->request.keep_alive = 0; struct epoll_event event = { .data.fd = conn->fd, .events = EPOLLOUT }; epoll_ctl(epoll_fd, EPOLL_CTL_MOD, conn->fd, &event); }