static void wps_er_http_req(void *ctx, struct http_request *req) { struct wps_er *er = ctx; struct sockaddr_in *cli = http_request_get_cli_addr(req); enum httpread_hdr_type type = http_request_get_type(req); struct wpabuf *buf; wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from " "%s:%d", http_request_get_uri(req), type, inet_ntoa(cli->sin_addr), ntohs(cli->sin_port)); switch (type) { case HTTPREAD_HDR_TYPE_NOTIFY: wps_er_http_notify(er, req); break; default: wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type " "%d", type); buf = wpabuf_alloc(200); if (buf == NULL) { http_request_deinit(req); return; } wpabuf_put_str(buf, "HTTP/1.1 501 Unimplemented\r\n" "Connection: close\r\n"); http_put_date(buf); wpabuf_put_str(buf, "\r\n"); http_request_send_and_deinit(req, buf); break; } }
static void http_req(void *ctx, struct http_request *req) { struct browser_data *data = ctx; struct wpabuf *resp; const char *url; int done = 0; url = http_request_get_uri(req); wpa_printf(MSG_INFO, "Browser response received: %s", url); if (os_strcmp(url, "/") == 0) { data->success = 1; done = 1; } else if (os_strncmp(url, "/osu/", 5) == 0) { data->success = atoi(url + 5); done = 1; } resp = wpabuf_alloc(1); if (resp == NULL) { http_request_deinit(req); if (done) eloop_terminate(); return; } if (done) { eloop_cancel_timeout(browser_timeout, NULL, NULL); eloop_register_timeout(0, 500000, browser_timeout, &data, NULL); } http_request_send_and_deinit(req, resp); }
static void wps_er_http_resp_not_found(struct http_request *req) { struct wpabuf *buf; buf = wpabuf_alloc(200); if (buf == NULL) { http_request_deinit(req); return; } wpabuf_put_str(buf, "HTTP/1.1 404 Not Found\r\n" "Server: unspecified, UPnP/1.0, unspecified\r\n" "Connection: close\r\n"); http_put_date(buf); wpabuf_put_str(buf, "\r\n"); http_request_send_and_deinit(req, buf); }
static void web_connection_send_reply(struct http_request *req, enum http_reply_code ret, const char *action, int action_len, const struct wpabuf *reply, const char *replyname) { struct wpabuf *buf; char *replydata; char *put_length_here = NULL; char *body_start = NULL; if (reply) { size_t len; replydata = (char *) base64_encode(wpabuf_head(reply), wpabuf_len(reply), &len); } else replydata = NULL; /* Parameters of the response: * action(action_len) -- action we are responding to * replyname -- a name we need for the reply * replydata -- NULL or null-terminated string */ buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) + (action_len > 0 ? action_len * 2 : 0)); if (buf == NULL) { wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to " "POST"); os_free(replydata); http_request_deinit(req); return; } /* * Assuming we will be successful, put in the output header first. * Note: we do not keep connections alive (and httpread does * not support it)... therefore we must have Connection: close. */ if (ret == HTTP_OK) { wpabuf_put_str(buf, "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; " "charset=\"utf-8\"\r\n"); } else { wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret); } wpabuf_put_str(buf, http_connection_close); wpabuf_put_str(buf, "Content-Length: "); /* * We will paste the length in later, leaving some extra whitespace. * HTTP code is supposed to be tolerant of extra whitespace. */ put_length_here = wpabuf_put(buf, 0); wpabuf_put_str(buf, " \r\n"); http_put_date(buf); /* terminating empty line */ wpabuf_put_str(buf, "\r\n"); body_start = wpabuf_put(buf, 0); if (ret == HTTP_OK) { wpabuf_put_str(buf, soap_prefix); wpabuf_put_str(buf, "<u:"); wpabuf_put_data(buf, action, action_len); wpabuf_put_str(buf, "Response xmlns:u=\""); wpabuf_put_str(buf, urn_wfawlanconfig); wpabuf_put_str(buf, "\">\n"); if (replydata && replyname) { /* TODO: might possibly need to escape part of reply * data? ... * probably not, unlikely to have ampersand(&) or left * angle bracket (<) in it... */ wpabuf_printf(buf, "<%s>", replyname); wpabuf_put_str(buf, replydata); wpabuf_printf(buf, "</%s>\n", replyname); } wpabuf_put_str(buf, "</u:"); wpabuf_put_data(buf, action, action_len); wpabuf_put_str(buf, "Response>\n"); wpabuf_put_str(buf, soap_postfix); } else { /* Error case */ wpabuf_put_str(buf, soap_prefix); wpabuf_put_str(buf, soap_error_prefix); wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret); wpabuf_put_str(buf, soap_error_postfix); wpabuf_put_str(buf, soap_postfix); } os_free(replydata); /* Now patch in the content length at the end */ if (body_start && put_length_here) { int body_length = (char *) wpabuf_put(buf, 0) - body_start; char len_buf[10]; os_snprintf(len_buf, sizeof(len_buf), "%d", body_length); os_memcpy(put_length_here, len_buf, os_strlen(len_buf)); } http_request_send_and_deinit(req, buf); }
/* Given that we have received a header w/ GET, act upon it * * Format of GET (case-insensitive): * * First line must be: * GET /<file> HTTP/1.1 * Since we don't do anything fancy we just ignore other lines. * * Our response (if no error) which includes only required lines is: * HTTP/1.1 200 OK * Connection: close * Content-Type: text/xml * Date: <rfc1123-date> * * Header lines must end with \r\n * Per RFC 2616, content-length: is not required but connection:close * would appear to be required (given that we will be closing it!). */ static void web_connection_parse_get(struct upnp_wps_device_sm *sm, struct http_request *hreq, char *filename) { struct wpabuf *buf; /* output buffer, allocated */ char *put_length_here; char *body_start; enum { GET_DEVICE_XML_FILE, GET_SCPD_XML_FILE } req; size_t extra_len = 0; int body_length; char len_buf[10]; struct upnp_wps_device_interface *iface; iface = dl_list_first(&sm->interfaces, struct upnp_wps_device_interface, list); if (iface == NULL) { http_request_deinit(hreq); return; } /* * It is not required that filenames be case insensitive but it is * allowed and cannot hurt here. */ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) { wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML"); req = GET_DEVICE_XML_FILE; extra_len = 3000; if (iface->wps->friendly_name) extra_len += os_strlen(iface->wps->friendly_name); if (iface->wps->manufacturer_url) extra_len += os_strlen(iface->wps->manufacturer_url); if (iface->wps->model_description) extra_len += os_strlen(iface->wps->model_description); if (iface->wps->model_url) extra_len += os_strlen(iface->wps->model_url); if (iface->wps->upc) extra_len += os_strlen(iface->wps->upc); } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) { wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML"); req = GET_SCPD_XML_FILE; extra_len = os_strlen(wps_scpd_xml); } else { /* File not found */ wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s", filename); buf = wpabuf_alloc(200); if (buf == NULL) { http_request_deinit(hreq); return; } wpabuf_put_str(buf, "HTTP/1.1 404 Not Found\r\n" "Connection: close\r\n"); http_put_date(buf); /* terminating empty line */ wpabuf_put_str(buf, "\r\n"); goto send_buf; } buf = wpabuf_alloc(1000 + extra_len); if (buf == NULL) { http_request_deinit(hreq); return; } wpabuf_put_str(buf, "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; charset=\"utf-8\"\r\n"); wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n"); wpabuf_put_str(buf, "Connection: close\r\n"); wpabuf_put_str(buf, "Content-Length: "); /* * We will paste the length in later, leaving some extra whitespace. * HTTP code is supposed to be tolerant of extra whitespace. */ put_length_here = wpabuf_put(buf, 0); wpabuf_put_str(buf, " \r\n"); http_put_date(buf); /* terminating empty line */ wpabuf_put_str(buf, "\r\n"); body_start = wpabuf_put(buf, 0); switch (req) { case GET_DEVICE_XML_FILE: format_wps_device_xml(iface, sm, buf); break; case GET_SCPD_XML_FILE: wpabuf_put_str(buf, wps_scpd_xml); break; } /* Now patch in the content length at the end */ body_length = (char *) wpabuf_put(buf, 0) - body_start; os_snprintf(len_buf, 10, "%d", body_length); os_memcpy(put_length_here, len_buf, os_strlen(len_buf)); send_buf: http_request_send_and_deinit(hreq, buf); }