/* Reads data from io->sock into io->read_meta_buf. If @to_blank is * %TRUE, it reads up until a blank line ("CRLF CRLF" or "LF LF"). * Otherwise, it reads up until a single CRLF or LF. * * This function is used to read metadata, and read_body_chunk() is * used to read the message body contents. * * read_metadata, read_body_chunk, and write_data all use the same * convention for return values: if they return %TRUE, it means * they've completely finished the requested read/write, and the * caller should move on to the next step. If they return %FALSE, it * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK, * so the caller should give up for now and wait for the socket to * emit a signal, or (b) the socket returned an error, and io_error() * was called to process it and cancel the I/O. So either way, if the * function returns %FALSE, the caller should return immediately. */ static gboolean read_metadata (SoupMessage *msg, gboolean to_blank) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; SoupSocketIOStatus status; guchar read_buf[RESPONSE_BLOCK_SIZE]; gsize nread; gboolean got_lf; GError *error = NULL; while (1) { status = soup_socket_read_until (io->sock, read_buf, sizeof (read_buf), "\n", 1, &nread, &got_lf, NULL, &error); switch (status) { case SOUP_SOCKET_OK: g_byte_array_append (io->read_meta_buf, read_buf, nread); break; case SOUP_SOCKET_ERROR: case SOUP_SOCKET_EOF: io_error (io->sock, msg, error); return FALSE; case SOUP_SOCKET_WOULD_BLOCK: return FALSE; } if (got_lf) { if (!to_blank) break; if (nread == 1 && !strncmp ((char *)io->read_meta_buf->data + io->read_meta_buf->len - 2, "\n\n", 2)) break; else if (nread == 2 && !strncmp ((char *)io->read_meta_buf->data + io->read_meta_buf->len - 3, "\n\r\n", 3)) break; } } if (soup_socket_is_ssl (io->sock)) { gboolean trusted_certificate; g_object_get (io->sock, SOUP_SOCKET_TRUSTED_CERTIFICATE, &trusted_certificate, NULL); if (trusted_certificate) soup_message_set_flags (msg, priv->msg_flags | SOUP_MESSAGE_CERTIFICATE_TRUSTED); } return TRUE; }
static guint parse_request_headers (SoupMessage *msg, char *headers, guint headers_len, SoupEncoding *encoding, gpointer sock) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); char *req_method, *req_path, *url; SoupHTTPVersion version; const char *req_host; guint status; SoupURI *uri; status = soup_headers_parse_request (headers, headers_len, msg->request_headers, &req_method, &req_path, &version); if (!SOUP_STATUS_IS_SUCCESSFUL (status)) return status; g_object_set (G_OBJECT (msg), SOUP_MESSAGE_METHOD, req_method, SOUP_MESSAGE_HTTP_VERSION, version, NULL); g_free (req_method); /* Handle request body encoding */ *encoding = soup_message_headers_get_encoding (msg->request_headers); if (*encoding == SOUP_ENCODING_UNRECOGNIZED) { if (soup_message_headers_get_list (msg->request_headers, "Transfer-Encoding")) return SOUP_STATUS_NOT_IMPLEMENTED; else return SOUP_STATUS_BAD_REQUEST; } /* Generate correct context for request */ req_host = soup_message_headers_get_one (msg->request_headers, "Host"); if (req_host && strchr (req_host, '/')) { g_free (req_path); return SOUP_STATUS_BAD_REQUEST; } if (!strcmp (req_path, "*") && req_host) { /* Eg, "OPTIONS * HTTP/1.1" */ url = g_strdup_printf ("%s://%s", soup_socket_is_ssl (sock) ? "https" : "http", req_host); uri = soup_uri_new (url); if (uri) soup_uri_set_path (uri, "*"); g_free (url); } else if (*req_path != '/') { /* Must be an absolute URI */ uri = soup_uri_new (req_path); } else if (req_host) { url = g_strdup_printf ("%s://%s%s", soup_socket_is_ssl (sock) ? "https" : "http", req_host, req_path); uri = soup_uri_new (url); g_free (url); } else if (priv->http_version == SOUP_HTTP_1_0) { /* No Host header, no AbsoluteUri */ SoupAddress *addr = soup_socket_get_local_address (sock); uri = soup_uri_new (NULL); soup_uri_set_scheme (uri, soup_socket_is_ssl (sock) ? SOUP_URI_SCHEME_HTTPS : SOUP_URI_SCHEME_HTTP); soup_uri_set_host (uri, soup_address_get_physical (addr)); soup_uri_set_port (uri, soup_address_get_port (addr)); soup_uri_set_path (uri, req_path); } else uri = NULL; g_free (req_path); if (!SOUP_URI_VALID_FOR_HTTP (uri)) { /* certainly not "a valid host on the server" (RFC2616 5.2.3) * SOUP_URI_VALID_FOR_HTTP also guards against uri == NULL */ if (uri) soup_uri_free (uri); return SOUP_STATUS_BAD_REQUEST; } soup_message_set_uri (msg, uri); soup_uri_free (uri); return SOUP_STATUS_OK; }