static int callback_http(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { #if 0 char client_name[128]; char client_ip[128]; #endif char buf[256]; char leaf_path[1024]; char b64[64]; struct timeval tv; int n, m; unsigned char *p; char *other_headers; static unsigned char buffer[4096]; struct stat stat_buf; struct per_session_data__http *pss = (struct per_session_data__http *)user; const char *mimetype; #ifdef EXTERNAL_POLL struct libwebsocket_pollargs *pa = (struct libwebsocket_pollargs *)in; #endif switch (reason) { case LWS_CALLBACK_HTTP: dump_handshake_info(wsi); if (len < 1) { libwebsockets_return_http_status(context, wsi, HTTP_STATUS_BAD_REQUEST, NULL); return -1; } /* this server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL); return -1; } /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; /* check for the "send a big file by hand" example case */ if (!strcmp((const char *)in, "/leaf.jpg")) { if (strlen(resource_path) > sizeof(leaf_path) - 10) return -1; sprintf(leaf_path, "%s/leaf.jpg", resource_path); /* well, let's demonstrate how to send the hard way */ p = buffer; #ifdef WIN32 pss->fd = open(leaf_path, O_RDONLY | _O_BINARY); #else pss->fd = open(leaf_path, O_RDONLY); #endif 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 * (too small for partial) */ 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 */ strcpy(buf, resource_path); if (strcmp(in, "/")) { if (*((const char *)in) != '/') strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(resource_path)); } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); libwebsockets_return_http_status(context, wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demostrates how to set a cookie on / */ other_headers = NULL; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); sprintf(b64, "LWS_%u_%u_COOKIE", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); sprintf(leaf_path, "Set-Cookie: test=LWS_%u_%u_COOKIE;Max-Age=360000\x0d\x0a", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); other_headers = leaf_path; lwsl_err(other_headers); } if (libwebsockets_serve_http_file(context, wsi, buf, mimetype, other_headers)) return -1; /* through completion or error, close the socket */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: strncpy(buf, in, 20); buf[20] = '\0'; if (len < 20) buf[len] = '\0'; lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n", (const char *)buf, (int)len); break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* the whole of the sent body arried, close the connection */ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_OK, NULL); return -1; 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; 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 flush_bail; /* * because it's HTTP and not websocket, don't need to take * care about pre and postamble */ m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP); if (m < 0) /* write failed, close conn */ goto bail; if (m != n) /* partial write, adjust */ lseek(pss->fd, m - n, SEEK_CUR); } while (!lws_send_pipe_choked(wsi)); libwebsocket_callback_on_writable(context, wsi); break; flush_bail: /* true if still partial pending */ if (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 * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default uhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: #if 0 libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name, sizeof(client_name), client_ip, sizeof(client_ip)); fprintf(stderr, "Received network connect from %s (%s)\n", client_name, client_ip); #endif /* if we returned non-zero from here, we kill the connection */ break; #ifdef EXTERNAL_POLL /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: /* * lock mutex to protect pollfd state * called before any other POLL related callback */ break; case LWS_CALLBACK_UNLOCK_POLL: /* * unlock mutex to protect pollfd state when * called after any other POLL related callback */ break; case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; m = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; #endif case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "libwebsocket_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; default: break; } return 0; }
static int callback_http(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { #if 0 char client_name[128]; char client_ip[128]; #endif char buf[256]; int n, m; unsigned char *p; static unsigned char buffer[4096]; struct stat stat_buf; struct per_session_data__http *pss = (struct per_session_data__http *)user; #ifdef EXTERNAL_POLL int fd = (int)(long)in; #endif 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 * (too small for partial) */ 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; 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 */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; 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; 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 */ m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP); if (m < 0) /* write failed, close conn */ goto bail; if (m != n) /* partial write, adjust */ lseek(pss->fd, m - n, SEEK_CUR); } 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 * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default uhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: #if 0 libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name, sizeof(client_name), client_ip, sizeof(client_ip)); fprintf(stderr, "Received network connect from %s (%s)\n", client_name, client_ip); #endif /* if we returned non-zero from here, we kill the connection */ break; #ifdef EXTERNAL_POLL /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[fd] = count_pollfds; pollfds[count_pollfds].fd = fd; pollfds[count_pollfds].events = (int)(long)len; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; m = fd_lookup[fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_SET_MODE_POLL_FD: pollfds[fd_lookup[fd]].events |= (int)(long)len; break; case LWS_CALLBACK_CLEAR_MODE_POLL_FD: pollfds[fd_lookup[fd]].events &= ~(int)(long)len; break; #endif default: break; } return 0; }
static int callback_http(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { (void)user; char buf[256]; char leaf_path[1024]; char b64[64]; struct timeval tv; char *other_headers; const char *mimetype; switch (reason) { case LWS_CALLBACK_HTTP: dump_handshake_info(wsi); if (len < 1) { libwebsockets_return_http_status(context, wsi, HTTP_STATUS_BAD_REQUEST, NULL); return -1; } /* this server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL); return -1; } /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; /* if not, send a file the easy way */ strcpy(buf, resource_path); if (strcmp((const char*)in, "/")) { strcat(buf, "/"); strncat(buf, (char*)in, sizeof(buf) - strlen(resource_path)); }else{ /* default file to serve */ strcat(buf, "/monitor.html"); } buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); libwebsockets_return_http_status(context, wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demostrates how to set a cookie on / */ other_headers = NULL; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); sprintf(b64, "LWS_%u_%u_COOKIE", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); sprintf(leaf_path, "Set-Cookie: test=LWS_%u_%u_COOKIE;Max-Age=360000\x0d\x0a", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); other_headers = leaf_path; lwsl_err(other_headers); } if (libwebsockets_serve_http_file(context, wsi, buf, mimetype, other_headers)){ return -1; /* through completion or error, close the socket */ } break; case LWS_CALLBACK_HTTP_BODY: strncpy(buf, (char*)in, 20); buf[20] = '\0'; if (len < 20) buf[len] = '\0'; lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n", (const char *)buf, (int)len); break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* the whole of the sent body arried, close the connection */ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_OK, NULL); return -1; case LWS_CALLBACK_HTTP_FILE_COMPLETION: /* kill the connection after we sent one file */ return -1; case LWS_CALLBACK_HTTP_WRITEABLE: return -1; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default uhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: #if 0 libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name, sizeof(client_name), client_ip, sizeof(client_ip)); fprintf(stderr, "Received network connect from %s (%s)\n", client_name, client_ip); #endif /* if we returned non-zero from here, we kill the connection */ break; case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "libwebsocket_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; default: break; } return 0; }