WPS: Read HTTP request within HTTP server code
This removes HTTP related code from wps_upnp_web.c and makes it easier to use HTTP server functionality for new uses (e.g., WPS ER).
This commit is contained in:
parent
b905c4a398
commit
875a4e5936
5 changed files with 255 additions and 174 deletions
|
@ -17,24 +17,197 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "eloop.h"
|
#include "eloop.h"
|
||||||
|
#include "httpread.h"
|
||||||
#include "http_server.h"
|
#include "http_server.h"
|
||||||
|
|
||||||
|
#define HTTP_SERVER_TIMEOUT 30
|
||||||
|
#define HTTP_SERVER_MAX_REQ_LEN 8000
|
||||||
|
#define HTTP_SERVER_MAX_CONNECTIONS 10
|
||||||
|
|
||||||
|
struct http_request {
|
||||||
|
struct http_request *next;
|
||||||
|
struct http_server *srv;
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in cli;
|
||||||
|
struct httpread *hread;
|
||||||
|
};
|
||||||
|
|
||||||
struct http_server {
|
struct http_server {
|
||||||
void (*cb)(void *ctx, int fd, struct sockaddr_in *addr);
|
void (*cb)(void *ctx, struct http_request *req);
|
||||||
void *cb_ctx;
|
void *cb_ctx;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
|
struct http_request *requests;
|
||||||
|
unsigned int request_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void http_request_cb(struct httpread *handle, void *cookie,
|
||||||
|
enum httpread_event en)
|
||||||
|
{
|
||||||
|
struct http_request *req = cookie;
|
||||||
|
struct http_server *srv = req->srv;
|
||||||
|
|
||||||
|
if (en == HTTPREAD_EVENT_FILE_READY) {
|
||||||
|
wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received",
|
||||||
|
inet_ntoa(req->cli.sin_addr),
|
||||||
|
ntohs(req->cli.sin_port));
|
||||||
|
srv->cb(srv->cb_ctx, req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received "
|
||||||
|
"completely", inet_ntoa(req->cli.sin_addr),
|
||||||
|
ntohs(req->cli.sin_port));
|
||||||
|
http_request_deinit(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct http_request * http_request_init(struct http_server *srv, int fd,
|
||||||
|
struct sockaddr_in *cli)
|
||||||
|
{
|
||||||
|
struct http_request *req;
|
||||||
|
|
||||||
|
if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) {
|
||||||
|
wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
req = os_zalloc(sizeof(*req));
|
||||||
|
if (req == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
req->srv = srv;
|
||||||
|
req->fd = fd;
|
||||||
|
req->cli = *cli;
|
||||||
|
|
||||||
|
req->hread = httpread_create(req->fd, http_request_cb, req,
|
||||||
|
HTTP_SERVER_MAX_REQ_LEN,
|
||||||
|
HTTP_SERVER_TIMEOUT);
|
||||||
|
if (req->hread == NULL) {
|
||||||
|
http_request_deinit(req);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void http_request_deinit(struct http_request *req)
|
||||||
|
{
|
||||||
|
struct http_request *r, *p;
|
||||||
|
struct http_server *srv;
|
||||||
|
|
||||||
|
if (req == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
srv = req->srv;
|
||||||
|
p = NULL;
|
||||||
|
r = srv->requests;
|
||||||
|
while (r) {
|
||||||
|
if (r == req) {
|
||||||
|
if (p)
|
||||||
|
p->next = r->next;
|
||||||
|
else
|
||||||
|
srv->requests = r->next;
|
||||||
|
srv->request_count--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = r;
|
||||||
|
r = r->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpread_destroy(req->hread);
|
||||||
|
close(req->fd);
|
||||||
|
os_free(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void http_request_free_all(struct http_request *req)
|
||||||
|
{
|
||||||
|
struct http_request *prev;
|
||||||
|
while (req) {
|
||||||
|
prev = req;
|
||||||
|
req = req->next;
|
||||||
|
http_request_deinit(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void http_request_send(struct http_request *req, struct wpabuf *resp)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d",
|
||||||
|
wpabuf_len(resp), inet_ntoa(req->cli.sin_addr),
|
||||||
|
ntohs(req->cli.sin_port));
|
||||||
|
|
||||||
|
res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0);
|
||||||
|
if (res < 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s",
|
||||||
|
strerror(errno));
|
||||||
|
} else if ((size_t) res < wpabuf_len(resp)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes",
|
||||||
|
res, (unsigned long) wpabuf_len(resp));
|
||||||
|
/* TODO: add eloop handler for sending rest of the data */
|
||||||
|
}
|
||||||
|
|
||||||
|
wpabuf_free(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void http_request_send_and_deinit(struct http_request *req,
|
||||||
|
struct wpabuf *resp)
|
||||||
|
{
|
||||||
|
http_request_send(req, resp);
|
||||||
|
http_request_deinit(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum httpread_hdr_type http_request_get_type(struct http_request *req)
|
||||||
|
{
|
||||||
|
return httpread_hdr_type_get(req->hread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * http_request_get_uri(struct http_request *req)
|
||||||
|
{
|
||||||
|
return httpread_uri_get(req->hread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * http_request_get_hdr(struct http_request *req)
|
||||||
|
{
|
||||||
|
return httpread_hdr_get(req->hread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * http_request_get_data(struct http_request *req)
|
||||||
|
{
|
||||||
|
return httpread_data_get(req->hread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * http_request_get_hdr_line(struct http_request *req, const char *tag)
|
||||||
|
{
|
||||||
|
return httpread_hdr_line_get(req->hread, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct sockaddr_in * http_request_get_cli_addr(struct http_request *req)
|
||||||
|
{
|
||||||
|
return &req->cli;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
|
static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
socklen_t addr_len = sizeof(addr);
|
socklen_t addr_len = sizeof(addr);
|
||||||
struct http_server *srv = eloop_ctx;
|
struct http_server *srv = eloop_ctx;
|
||||||
int conn;
|
int conn;
|
||||||
|
struct http_request *req;
|
||||||
|
|
||||||
conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len);
|
conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len);
|
||||||
if (conn < 0) {
|
if (conn < 0) {
|
||||||
|
@ -44,13 +217,22 @@ static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
|
||||||
}
|
}
|
||||||
wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d",
|
wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d",
|
||||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||||||
srv->cb(srv->cb_ctx, conn, &addr);
|
|
||||||
|
req = http_request_init(srv, conn, &addr);
|
||||||
|
if (req == NULL) {
|
||||||
|
close(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->next = srv->requests;
|
||||||
|
srv->requests = req;
|
||||||
|
srv->request_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct http_server * http_server_init(struct in_addr *addr, int port,
|
struct http_server * http_server_init(struct in_addr *addr, int port,
|
||||||
void (*cb)(void *ctx, int fd,
|
void (*cb)(void *ctx,
|
||||||
struct sockaddr_in *addr),
|
struct http_request *req),
|
||||||
void *cb_ctx)
|
void *cb_ctx)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
|
@ -117,6 +299,7 @@ void http_server_deinit(struct http_server *srv)
|
||||||
eloop_unregister_sock(srv->fd, EVENT_TYPE_READ);
|
eloop_unregister_sock(srv->fd, EVENT_TYPE_READ);
|
||||||
close(srv->fd);
|
close(srv->fd);
|
||||||
}
|
}
|
||||||
|
http_request_free_all(srv->requests);
|
||||||
|
|
||||||
os_free(srv);
|
os_free(srv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,22 @@
|
||||||
#define HTTP_SERVER_H
|
#define HTTP_SERVER_H
|
||||||
|
|
||||||
struct http_server;
|
struct http_server;
|
||||||
|
struct http_request;
|
||||||
|
|
||||||
|
void http_request_deinit(struct http_request *req);
|
||||||
|
void http_request_send(struct http_request *req, struct wpabuf *resp);
|
||||||
|
void http_request_send_and_deinit(struct http_request *req,
|
||||||
|
struct wpabuf *resp);
|
||||||
|
enum httpread_hdr_type http_request_get_type(struct http_request *req);
|
||||||
|
char * http_request_get_uri(struct http_request *req);
|
||||||
|
char * http_request_get_hdr(struct http_request *req);
|
||||||
|
char * http_request_get_data(struct http_request *req);
|
||||||
|
char * http_request_get_hdr_line(struct http_request *req, const char *tag);
|
||||||
|
struct sockaddr_in * http_request_get_cli_addr(struct http_request *req);
|
||||||
|
|
||||||
struct http_server * http_server_init(struct in_addr *addr, int port,
|
struct http_server * http_server_init(struct in_addr *addr, int port,
|
||||||
void (*cb)(void *ctx, int fd,
|
void (*cb)(void *ctx,
|
||||||
struct sockaddr_in *addr),
|
struct http_request *req),
|
||||||
void *cb_ctx);
|
void *cb_ctx);
|
||||||
void http_server_deinit(struct http_server *srv);
|
void http_server_deinit(struct http_server *srv);
|
||||||
int http_server_get_port(struct http_server *srv);
|
int http_server_get_port(struct http_server *srv);
|
||||||
|
|
|
@ -956,8 +956,6 @@ void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
|
wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
|
||||||
web_listener_stop(sm);
|
web_listener_stop(sm);
|
||||||
while (sm->web_connections)
|
|
||||||
web_connection_stop(sm->web_connections);
|
|
||||||
while (sm->msearch_replies)
|
while (sm->msearch_replies)
|
||||||
msearchreply_state_machine_stop(sm->msearch_replies);
|
msearchreply_state_machine_stop(sm->msearch_replies);
|
||||||
while (sm->subscriptions) {
|
while (sm->subscriptions) {
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */
|
#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */
|
||||||
|
|
||||||
|
|
||||||
struct web_connection;
|
|
||||||
struct subscription;
|
struct subscription;
|
||||||
struct upnp_wps_device_sm;
|
struct upnp_wps_device_sm;
|
||||||
|
|
||||||
|
@ -131,8 +130,6 @@ struct upnp_wps_device_sm {
|
||||||
int n_msearch_replies; /* no. of pending M-SEARCH replies */
|
int n_msearch_replies; /* no. of pending M-SEARCH replies */
|
||||||
int web_port; /* our port that others get xml files from */
|
int web_port; /* our port that others get xml files from */
|
||||||
struct http_server *web_srv;
|
struct http_server *web_srv;
|
||||||
struct web_connection *web_connections; /* linked list */
|
|
||||||
int n_web_connections; /* no. of pending web connections */
|
|
||||||
/* Note: subscriptions are kept in expiry order */
|
/* Note: subscriptions are kept in expiry order */
|
||||||
struct subscription *subscriptions; /* linked list */
|
struct subscription *subscriptions; /* linked list */
|
||||||
int n_subscriptions; /* no of current subscriptions */
|
int n_subscriptions; /* no of current subscriptions */
|
||||||
|
@ -171,7 +168,6 @@ int ssdp_open_multicast_sock(u32 ip_addr);
|
||||||
int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
|
int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
|
||||||
|
|
||||||
/* wps_upnp_web.c */
|
/* wps_upnp_web.c */
|
||||||
void web_connection_stop(struct web_connection *c);
|
|
||||||
int web_listener_start(struct upnp_wps_device_sm *sm);
|
int web_listener_start(struct upnp_wps_device_sm *sm);
|
||||||
void web_listener_stop(struct upnp_wps_device_sm *sm);
|
void web_listener_stop(struct upnp_wps_device_sm *sm);
|
||||||
|
|
||||||
|
|
|
@ -37,28 +37,6 @@ static const char *http_server_hdr =
|
||||||
static const char *http_connection_close =
|
static const char *http_connection_close =
|
||||||
"Connection: close\r\n";
|
"Connection: close\r\n";
|
||||||
|
|
||||||
/*
|
|
||||||
* Incoming web connections are recorded in this struct.
|
|
||||||
* A web connection is a TCP connection to us, the server;
|
|
||||||
* it is called a "web connection" because we use http and serve
|
|
||||||
* data that looks like web pages.
|
|
||||||
* State information is need to track the connection until we figure
|
|
||||||
* out what they want and what we want to do about it.
|
|
||||||
*/
|
|
||||||
struct web_connection {
|
|
||||||
/* double linked list */
|
|
||||||
struct web_connection *next;
|
|
||||||
struct web_connection *prev;
|
|
||||||
struct upnp_wps_device_sm *sm; /* parent */
|
|
||||||
int sd; /* socket to read from */
|
|
||||||
struct sockaddr_in cli_addr;
|
|
||||||
int sd_registered; /* nonzero if we must cancel registration */
|
|
||||||
struct httpread *hread; /* state machine for reading socket */
|
|
||||||
int n_rcvd_data; /* how much data read so far */
|
|
||||||
int done; /* internal flag, set when we've finished */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Files" that we serve via HTTP. The format of these files is given by
|
* "Files" that we serve via HTTP. The format of these files is given by
|
||||||
* WFA WPS specifications. Extra white space has been removed to save space.
|
* WFA WPS specifications. Extra white space has been removed to save space.
|
||||||
|
@ -378,27 +356,6 @@ static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void web_connection_stop(struct web_connection *c)
|
|
||||||
{
|
|
||||||
struct upnp_wps_device_sm *sm = c->sm;
|
|
||||||
|
|
||||||
httpread_destroy(c->hread);
|
|
||||||
c->hread = NULL;
|
|
||||||
close(c->sd);
|
|
||||||
c->sd = -1;
|
|
||||||
if (c->next == c) {
|
|
||||||
sm->web_connections = NULL;
|
|
||||||
} else {
|
|
||||||
if (sm->web_connections == c)
|
|
||||||
sm->web_connections = c->next;
|
|
||||||
c->next->prev = c->prev;
|
|
||||||
c->prev->next = c->next;
|
|
||||||
}
|
|
||||||
os_free(c);
|
|
||||||
sm->n_web_connections--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
|
static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
|
||||||
{
|
{
|
||||||
wpabuf_put_str(buf, "HTTP/1.1 ");
|
wpabuf_put_str(buf, "HTTP/1.1 ");
|
||||||
|
@ -459,9 +416,9 @@ static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
|
||||||
* Per RFC 2616, content-length: is not required but connection:close
|
* Per RFC 2616, content-length: is not required but connection:close
|
||||||
* would appear to be required (given that we will be closing it!).
|
* would appear to be required (given that we will be closing it!).
|
||||||
*/
|
*/
|
||||||
static void web_connection_parse_get(struct web_connection *c, char *filename)
|
static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
|
||||||
|
struct http_request *hreq, char *filename)
|
||||||
{
|
{
|
||||||
struct upnp_wps_device_sm *sm = c->sm;
|
|
||||||
struct wpabuf *buf; /* output buffer, allocated */
|
struct wpabuf *buf; /* output buffer, allocated */
|
||||||
char *put_length_here;
|
char *put_length_here;
|
||||||
char *body_start;
|
char *body_start;
|
||||||
|
@ -502,8 +459,10 @@ static void web_connection_parse_get(struct web_connection *c, char *filename)
|
||||||
wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
|
wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
|
||||||
filename);
|
filename);
|
||||||
buf = wpabuf_alloc(200);
|
buf = wpabuf_alloc(200);
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
|
http_request_deinit(hreq);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
wpabuf_put_str(buf,
|
wpabuf_put_str(buf,
|
||||||
"HTTP/1.1 404 Not Found\r\n"
|
"HTTP/1.1 404 Not Found\r\n"
|
||||||
"Connection: close\r\n");
|
"Connection: close\r\n");
|
||||||
|
@ -517,8 +476,10 @@ static void web_connection_parse_get(struct web_connection *c, char *filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = wpabuf_alloc(1000 + extra_len);
|
buf = wpabuf_alloc(1000 + extra_len);
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
|
http_request_deinit(hreq);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wpabuf_put_str(buf,
|
wpabuf_put_str(buf,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
@ -555,8 +516,7 @@ static void web_connection_parse_get(struct web_connection *c, char *filename)
|
||||||
os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
|
os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
|
||||||
|
|
||||||
send_buf:
|
send_buf:
|
||||||
send_wpabuf(c->sd, buf);
|
http_request_send_and_deinit(hreq, buf);
|
||||||
wpabuf_free(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -940,7 +900,7 @@ static const char *soap_error_postfix =
|
||||||
"</detail>\n"
|
"</detail>\n"
|
||||||
"</s:Fault>\n";
|
"</s:Fault>\n";
|
||||||
|
|
||||||
static void web_connection_send_reply(struct web_connection *c,
|
static void web_connection_send_reply(struct http_request *req,
|
||||||
enum http_reply_code ret,
|
enum http_reply_code ret,
|
||||||
const char *action, int action_len,
|
const char *action, int action_len,
|
||||||
const struct wpabuf *reply,
|
const struct wpabuf *reply,
|
||||||
|
@ -968,8 +928,8 @@ static void web_connection_send_reply(struct web_connection *c,
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
|
wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
|
||||||
"POST");
|
"POST");
|
||||||
wpabuf_free(buf);
|
|
||||||
os_free(replydata);
|
os_free(replydata);
|
||||||
|
http_request_deinit(req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1042,12 +1002,11 @@ static void web_connection_send_reply(struct web_connection *c,
|
||||||
os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
|
os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
send_wpabuf(c->sd, buf);
|
http_request_send_and_deinit(req, buf);
|
||||||
wpabuf_free(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char * web_get_action(struct web_connection *c,
|
static const char * web_get_action(struct http_request *req,
|
||||||
const char *filename, size_t *action_len)
|
const char *filename, size_t *action_len)
|
||||||
{
|
{
|
||||||
const char *match;
|
const char *match;
|
||||||
|
@ -1062,7 +1021,7 @@ static const char * web_get_action(struct web_connection *c,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* The SOAPAction line of the header tells us what we want to do */
|
/* The SOAPAction line of the header tells us what we want to do */
|
||||||
b = httpread_hdr_line_get(c->hread, "SOAPAction:");
|
b = http_request_get_hdr_line(req, "SOAPAction:");
|
||||||
if (b == NULL)
|
if (b == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (*b == '"')
|
if (*b == '"')
|
||||||
|
@ -1109,19 +1068,19 @@ static const char * web_get_action(struct web_connection *c,
|
||||||
* Per RFC 2616, content-length: is not required but connection:close
|
* Per RFC 2616, content-length: is not required but connection:close
|
||||||
* would appear to be required (given that we will be closing it!).
|
* would appear to be required (given that we will be closing it!).
|
||||||
*/
|
*/
|
||||||
static void web_connection_parse_post(struct web_connection *c,
|
static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
|
||||||
|
struct http_request *req,
|
||||||
const char *filename)
|
const char *filename)
|
||||||
{
|
{
|
||||||
enum http_reply_code ret;
|
enum http_reply_code ret;
|
||||||
struct upnp_wps_device_sm *sm = c->sm;
|
char *data = http_request_get_data(req); /* body of http msg */
|
||||||
char *data = httpread_data_get(c->hread); /* body of http msg */
|
|
||||||
const char *action;
|
const char *action;
|
||||||
size_t action_len;
|
size_t action_len;
|
||||||
const char *replyname = NULL; /* argument name for the reply */
|
const char *replyname = NULL; /* argument name for the reply */
|
||||||
struct wpabuf *reply = NULL; /* data for the reply */
|
struct wpabuf *reply = NULL; /* data for the reply */
|
||||||
|
|
||||||
ret = UPNP_INVALID_ACTION;
|
ret = UPNP_INVALID_ACTION;
|
||||||
action = web_get_action(c, filename, &action_len);
|
action = web_get_action(req, filename, &action_len);
|
||||||
if (action == NULL)
|
if (action == NULL)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
|
@ -1172,7 +1131,7 @@ static void web_connection_parse_post(struct web_connection *c,
|
||||||
bad:
|
bad:
|
||||||
if (ret != HTTP_OK)
|
if (ret != HTTP_OK)
|
||||||
wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
|
wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
|
||||||
web_connection_send_reply(c, ret, action, action_len, reply,
|
web_connection_send_reply(req, ret, action, action_len, reply,
|
||||||
replyname);
|
replyname);
|
||||||
wpabuf_free(reply);
|
wpabuf_free(reply);
|
||||||
}
|
}
|
||||||
|
@ -1197,13 +1156,13 @@ bad:
|
||||||
* Per RFC 2616, content-length: is not required but connection:close
|
* Per RFC 2616, content-length: is not required but connection:close
|
||||||
* would appear to be required (given that we will be closing it!).
|
* would appear to be required (given that we will be closing it!).
|
||||||
*/
|
*/
|
||||||
static void web_connection_parse_subscribe(struct web_connection *c,
|
static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
|
||||||
|
struct http_request *req,
|
||||||
const char *filename)
|
const char *filename)
|
||||||
{
|
{
|
||||||
struct upnp_wps_device_sm *sm = c->sm;
|
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
char *b;
|
char *b;
|
||||||
char *hdr = httpread_hdr_get(c->hread);
|
char *hdr = http_request_get_hdr(req);
|
||||||
char *h;
|
char *h;
|
||||||
char *match;
|
char *match;
|
||||||
int match_len;
|
int match_len;
|
||||||
|
@ -1217,8 +1176,10 @@ static void web_connection_parse_subscribe(struct web_connection *c,
|
||||||
enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
|
enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
|
||||||
buf = wpabuf_alloc(1000);
|
buf = wpabuf_alloc(1000);
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
|
http_request_deinit(req);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse/validate headers */
|
/* Parse/validate headers */
|
||||||
h = hdr;
|
h = hdr;
|
||||||
|
@ -1360,9 +1321,8 @@ static void web_connection_parse_subscribe(struct web_connection *c,
|
||||||
/* And empty line to terminate header: */
|
/* And empty line to terminate header: */
|
||||||
wpabuf_put_str(buf, "\r\n");
|
wpabuf_put_str(buf, "\r\n");
|
||||||
|
|
||||||
send_wpabuf(c->sd, buf);
|
|
||||||
wpabuf_free(buf);
|
|
||||||
os_free(callback_urls);
|
os_free(callback_urls);
|
||||||
|
http_request_send_and_deinit(req, buf);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -1388,8 +1348,7 @@ error:
|
||||||
* 599 Too many subscriptions (not a standard HTTP error)
|
* 599 Too many subscriptions (not a standard HTTP error)
|
||||||
*/
|
*/
|
||||||
http_put_empty(buf, ret);
|
http_put_empty(buf, ret);
|
||||||
send_wpabuf(c->sd, buf);
|
http_request_send_and_deinit(req, buf);
|
||||||
wpabuf_free(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1408,12 +1367,12 @@ error:
|
||||||
* Per RFC 2616, content-length: is not required but connection:close
|
* Per RFC 2616, content-length: is not required but connection:close
|
||||||
* would appear to be required (given that we will be closing it!).
|
* would appear to be required (given that we will be closing it!).
|
||||||
*/
|
*/
|
||||||
static void web_connection_parse_unsubscribe(struct web_connection *c,
|
static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
|
||||||
|
struct http_request *req,
|
||||||
const char *filename)
|
const char *filename)
|
||||||
{
|
{
|
||||||
struct upnp_wps_device_sm *sm = c->sm;
|
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
char *hdr = httpread_hdr_get(c->hread);
|
char *hdr = http_request_get_hdr(req);
|
||||||
char *h;
|
char *h;
|
||||||
char *match;
|
char *match;
|
||||||
int match_len;
|
int match_len;
|
||||||
|
@ -1500,40 +1459,42 @@ static void web_connection_parse_unsubscribe(struct web_connection *c,
|
||||||
|
|
||||||
send_msg:
|
send_msg:
|
||||||
buf = wpabuf_alloc(200);
|
buf = wpabuf_alloc(200);
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
|
http_request_deinit(req);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
http_put_empty(buf, ret);
|
http_put_empty(buf, ret);
|
||||||
send_wpabuf(c->sd, buf);
|
http_request_send_and_deinit(req, buf);
|
||||||
wpabuf_free(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send error in response to unknown requests */
|
/* Send error in response to unknown requests */
|
||||||
static void web_connection_unimplemented(struct web_connection *c)
|
static void web_connection_unimplemented(struct http_request *req)
|
||||||
{
|
{
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
buf = wpabuf_alloc(200);
|
buf = wpabuf_alloc(200);
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
|
http_request_deinit(req);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
http_put_empty(buf, HTTP_UNIMPLEMENTED);
|
http_put_empty(buf, HTTP_UNIMPLEMENTED);
|
||||||
send_wpabuf(c->sd, buf);
|
http_request_send_and_deinit(req, buf);
|
||||||
wpabuf_free(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Called when we have gotten an apparently valid http request.
|
/* Called when we have gotten an apparently valid http request.
|
||||||
*/
|
*/
|
||||||
static void web_connection_check_data(struct web_connection *c)
|
static void web_connection_check_data(void *ctx, struct http_request *req)
|
||||||
{
|
{
|
||||||
struct httpread *hread = c->hread;
|
struct upnp_wps_device_sm *sm = ctx;
|
||||||
enum httpread_hdr_type htype = httpread_hdr_type_get(hread);
|
enum httpread_hdr_type htype = http_request_get_type(req);
|
||||||
/* char *data = httpread_data_get(hread); */
|
char *filename = http_request_get_uri(req);
|
||||||
char *filename = httpread_uri_get(hread);
|
struct sockaddr_in *cli = http_request_get_cli_addr(req);
|
||||||
|
|
||||||
c->done = 1;
|
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
|
wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
|
||||||
|
http_request_deinit(req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Trim leading slashes from filename */
|
/* Trim leading slashes from filename */
|
||||||
|
@ -1541,22 +1502,22 @@ static void web_connection_check_data(struct web_connection *c)
|
||||||
filename++;
|
filename++;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
|
wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
|
||||||
htype, inet_ntoa(c->cli_addr.sin_addr),
|
htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
|
||||||
htons(c->cli_addr.sin_port));
|
|
||||||
|
|
||||||
switch (htype) {
|
switch (htype) {
|
||||||
case HTTPREAD_HDR_TYPE_GET:
|
case HTTPREAD_HDR_TYPE_GET:
|
||||||
web_connection_parse_get(c, filename);
|
web_connection_parse_get(sm, req, filename);
|
||||||
break;
|
break;
|
||||||
case HTTPREAD_HDR_TYPE_POST:
|
case HTTPREAD_HDR_TYPE_POST:
|
||||||
web_connection_parse_post(c, filename);
|
web_connection_parse_post(sm, req, filename);
|
||||||
break;
|
break;
|
||||||
case HTTPREAD_HDR_TYPE_SUBSCRIBE:
|
case HTTPREAD_HDR_TYPE_SUBSCRIBE:
|
||||||
web_connection_parse_subscribe(c, filename);
|
web_connection_parse_subscribe(sm, req, filename);
|
||||||
break;
|
break;
|
||||||
case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
|
case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
|
||||||
web_connection_parse_unsubscribe(c, filename);
|
web_connection_parse_unsubscribe(sm, req, filename);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* We are not required to support M-POST; just plain
|
/* We are not required to support M-POST; just plain
|
||||||
* POST is supposed to work, so we only support that.
|
* POST is supposed to work, so we only support that.
|
||||||
* If for some reason we need to support M-POST, it is
|
* If for some reason we need to support M-POST, it is
|
||||||
|
@ -1564,82 +1525,12 @@ static void web_connection_check_data(struct web_connection *c)
|
||||||
*/
|
*/
|
||||||
default:
|
default:
|
||||||
/* Send 501 for anything else */
|
/* Send 501 for anything else */
|
||||||
web_connection_unimplemented(c);
|
web_connection_unimplemented(req);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* called back when we have gotten request */
|
|
||||||
static void web_connection_got_file_handler(struct httpread *handle,
|
|
||||||
void *cookie,
|
|
||||||
enum httpread_event en)
|
|
||||||
{
|
|
||||||
struct web_connection *c = cookie;
|
|
||||||
|
|
||||||
if (en == HTTPREAD_EVENT_FILE_READY)
|
|
||||||
web_connection_check_data(c);
|
|
||||||
web_connection_stop(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* web_connection_start - Start web connection
|
|
||||||
* @sm: WPS UPnP state machine from upnp_wps_device_init()
|
|
||||||
* @sd: Socket descriptor
|
|
||||||
* @addr: Client address
|
|
||||||
*
|
|
||||||
* The socket descriptor sd is handed over for ownership by the WPS UPnP
|
|
||||||
* state machine.
|
|
||||||
*/
|
|
||||||
static void web_connection_start(void *ctx, int sd, struct sockaddr_in *addr)
|
|
||||||
{
|
|
||||||
struct upnp_wps_device_sm *sm = ctx;
|
|
||||||
struct web_connection *c = NULL;
|
|
||||||
|
|
||||||
/* if too many connections, bail */
|
|
||||||
if (sm->n_web_connections >= MAX_WEB_CONNECTIONS) {
|
|
||||||
close(sd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
c = os_zalloc(sizeof(*c));
|
|
||||||
if (c == NULL)
|
|
||||||
return;
|
|
||||||
os_memcpy(&c->cli_addr, addr, sizeof(c->cli_addr));
|
|
||||||
c->sm = sm;
|
|
||||||
c->sd = sd;
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* Setting non-blocking should not be necessary for read, and can mess
|
|
||||||
* up sending where blocking might be better.
|
|
||||||
*/
|
|
||||||
if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
c->hread = httpread_create(c->sd, web_connection_got_file_handler,
|
|
||||||
c /* cookie */,
|
|
||||||
WEB_CONNECTION_MAX_READ,
|
|
||||||
WEB_CONNECTION_TIMEOUT_SEC);
|
|
||||||
if (c->hread == NULL)
|
|
||||||
goto fail;
|
|
||||||
if (sm->web_connections) {
|
|
||||||
c->next = sm->web_connections;
|
|
||||||
c->prev = c->next->prev;
|
|
||||||
c->prev->next = c;
|
|
||||||
c->next->prev = c;
|
|
||||||
} else {
|
|
||||||
sm->web_connections = c->next = c->prev = c;
|
|
||||||
}
|
|
||||||
sm->n_web_connections++;
|
|
||||||
return;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
if (c)
|
|
||||||
web_connection_stop(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Listening for web connections
|
* Listening for web connections
|
||||||
* We have a single TCP listening port, and hand off connections as we get
|
* We have a single TCP listening port, and hand off connections as we get
|
||||||
|
@ -1657,7 +1548,8 @@ int web_listener_start(struct upnp_wps_device_sm *sm)
|
||||||
{
|
{
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
addr.s_addr = sm->ip_addr;
|
addr.s_addr = sm->ip_addr;
|
||||||
sm->web_srv = http_server_init(&addr, -1, web_connection_start, sm);
|
sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
|
||||||
|
sm);
|
||||||
if (sm->web_srv == NULL) {
|
if (sm->web_srv == NULL) {
|
||||||
web_listener_stop(sm);
|
web_listener_stop(sm);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Reference in a new issue