add by hand http send example

This adds a demonstration of how to use the http nonblocking
send action to the test server.

If you ask for /leaf.jpg from the test server, it will send
"by hand" a 2.4MB jpeg in HTTP, including the headers.  See
the test server sources to see how it is done.

Although it's a file, and a jpeg image, actually the exact
same scheme will work for any data or mime type.

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2013-02-14 23:06:37 +08:00
parent e803c82044
commit fbf48227b3
4 changed files with 96 additions and 6 deletions

View file

@ -109,7 +109,7 @@ libwebsockets_test_ping_CFLAGS= -Wall -Werror -std=gnu99 -pedantic -DINSTALL_DAT
endif
endif
EXTRA_DIST=test.html favicon.ico libwebsockets.org-logo.png
EXTRA_DIST=test.html favicon.ico libwebsockets.org-logo.png leaf.jpg
#
# cook a random test cert and key

BIN
test-server/leaf.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View file

@ -28,6 +28,8 @@
#include <getopt.h>
#include <string.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#ifdef WIN32
@ -104,6 +106,10 @@ static const struct serveable whitelist[] = {
{ "/test.html", "text/html" },
};
struct per_session_data__http {
int fd;
};
/* this protocol server (always the first one) just knows how to do HTTP */
static int callback_http(struct libwebsocket_context *context,
@ -117,6 +123,10 @@ static int callback_http(struct libwebsocket_context *context,
#endif
char buf[256];
int n;
unsigned char *p;
static unsigned char buffer[8192];
struct stat stat_buf;
struct per_session_data__http *pss = (struct per_session_data__http *)user;
#ifdef EXTERNAL_POLL
int m;
int fd = (int)(long)user;
@ -125,6 +135,55 @@ static int callback_http(struct libwebsocket_context *context,
switch (reason) {
case LWS_CALLBACK_HTTP:
/* check for the "send a big file by hand" example case */
if (!strcmp((const char *)in, "/leaf.jpg")) {
/* well, let's demonstrate how to send the hard way */
p = buffer;
pss->fd = open(LOCAL_RESOURCE_PATH"/leaf.jpg", O_RDONLY);
if (pss->fd < 0)
return -1;
fstat(pss->fd, &stat_buf);
/*
* we will send a big jpeg file, but it could be
* anything. Set the Content-Type: appropriately
* so the browser knows what to do with it.
*/
p += sprintf((char *)p,
"HTTP/1.0 200 OK\x0d\x0a"
"Server: libwebsockets\x0d\x0a"
"Content-Type: image-jpeg\x0d\x0a"
"Content-Length: %u\x0d\x0a\x0d\x0a",
(unsigned int)stat_buf.st_size);
/*
* send the http headers...
* this won't block since it's the first payload sent
* on the connection since it was established
*/
n = libwebsocket_write(wsi, buffer,
p - buffer, LWS_WRITE_HTTP);
if (n < 0) {
close(pss->fd);
return -1;
}
/*
* book us a LWS_CALLBACK_HTTP_WRITEABLE callback
*/
libwebsocket_callback_on_writable(context, wsi);
break;
}
/* if not, send a file the easy way */
for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
if (in && strcmp((const char *)in, whitelist[n].urlpath) == 0)
break;
@ -132,7 +191,7 @@ static int callback_http(struct libwebsocket_context *context,
sprintf(buf, LOCAL_RESOURCE_PATH"%s", whitelist[n].urlpath);
if (libwebsockets_serve_http_file(context, wsi, buf, whitelist[n].mimetype))
return 1; /* through completion or error, close the socket */
return -1; /* through completion or error, close the socket */
/*
* notice that the sending of the file completes asynchronously,
@ -145,7 +204,37 @@ static int callback_http(struct libwebsocket_context *context,
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n");
/* kill the connection after we sent one file */
return 1;
return -1;
case LWS_CALLBACK_HTTP_WRITEABLE:
/*
* we can send more of whatever it is we were sending
*/
do {
n = read(pss->fd, buffer, sizeof buffer);
/* problem reading, close conn */
if (n < 0)
goto bail;
/* sent it all, close conn */
if (n == 0)
goto bail;
/*
* because it's HTTP and not websocket, don't need to take
* care about pre and postamble
*/
n = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP);
if (n < 0)
/* write failed, close conn */
goto bail;
} while (!lws_send_pipe_choked(wsi));
libwebsocket_callback_on_writable(context, wsi);
break;
bail:
close(pss->fd);
return -1;
/*
* callback for confirming to continue with client IP appear in
@ -476,7 +565,7 @@ static struct libwebsocket_protocols protocols[] = {
{
"http-only", /* name */
callback_http, /* callback */
0, /* per_session_data_size */
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
},
{

View file

@ -37,8 +37,9 @@
The incrementing number is coming from the server and is individual for
each connection to the server... try opening a second browser window.
<br/><br/>
Click the button to send the server a websocket message to
reset the number.
The button zeros just this connection's number.
<br/><br/>
Click <a href="/leaf.jpg" target="_blank">Here</a> to have the test server send a big picture by http.
</td></tr></table>
</section>
<br>