add by hand http send example 05/3105/1
authorAndy Green <andy.green@linaro.org>
Thu, 14 Feb 2013 15:06:37 +0000 (23:06 +0800)
committerKevron Rees <kevron_m_rees@linux.intel.com>
Thu, 7 Mar 2013 21:01:36 +0000 (13:01 -0800)
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>
test-server/Makefile.am
test-server/leaf.jpg [new file with mode: 0644]
test-server/test-server.c
test-server/test.html

index 1159b37..b08460d 100644 (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
diff --git a/test-server/leaf.jpg b/test-server/leaf.jpg
new file mode 100644 (file)
index 0000000..1a3f46b
Binary files /dev/null and b/test-server/leaf.jpg differ
index ecf1dd1..246c1b8 100644 (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 */
        },
        {
index 482147e..919f46a 100644 (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>