Index: remoting/tools/client_webserver/main.c |
=================================================================== |
--- remoting/tools/client_webserver/main.c (revision 0) |
+++ remoting/tools/client_webserver/main.c (revision 0) |
@@ -0,0 +1,164 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// Simple webserver that returns empty content with the requested mimetype. |
+// |
+// For example: |
+// http://localhost:8080/pepper-application/x-chromoting-plugin |
+// Will return empty content, but with the requested mimetype: |
+// Content-Type: pepper-application/x-chromoting-plugin |
+// |
+// This is useful for testing the Chromoting plugin while we wait for |
+// updated mimetype support to be added to Chrome. |
+ |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string.h> |
+#include <sys/wait.h> |
+#include <netinet/in.h> |
+ |
+#define PORT 8080 |
+ |
+void error(const char *msg) { |
+ fprintf(stderr, "ERROR - %s\n", msg); |
+ exit(1); |
+} |
+ |
+// Read text data from a socket to a buffer. |
+// Data up to the next \n char is read into the buffer. |
+void read_text_data(int sock, char *buffer, int buffsize) { |
+ int num_bytes; |
+ *buffer = '\0'; |
+ |
+ for (num_bytes = 1; num_bytes < buffsize-1; num_bytes++) { |
+ char ch; |
+ |
+ int num_bytes_read = read(sock, &ch, 1); |
+ if (num_bytes_read == 1) { |
+ if (ch == '\n') { |
+ break; |
+ } |
+ *buffer++ = ch; |
+ } else if (num_bytes_read == 0) { |
+ break; |
+ } else { |
+ error("read_text_data failed"); |
+ } |
+ } |
+ *buffer++ = '\0'; |
+} |
+ |
+// Write data from a null-terminated buffer to a socket. |
+void write_data(int sock, const char *buffer) { |
+ int num_bytes = strlen(buffer); |
+ |
+ while (num_bytes > 0) { |
+ int num_bytes_written = write(sock, buffer, num_bytes); |
+ if (num_bytes_written <= 0) { |
+ error("write_data failed"); |
+ } |
+ num_bytes -= num_bytes_written; |
+ buffer += num_bytes_written; |
+ } |
+} |
+ |
+void handle_request(int connection) { |
+ printf("Handling request...\n"); |
+ char buffer[512]; |
+ buffer[0] = '\0'; |
+ |
+ // Read the first line of the request. This will be something like: |
+ // GET /index.html HTTP/1.1 |
+ read_text_data(connection, buffer, 512); |
+ |
+ char *saveptr; |
+ char *request = strtok_r(buffer, " ", &saveptr); |
+ char *resource = strtok_r(NULL, " ", &saveptr); |
+ char *version = strtok_r(NULL, " ", &saveptr); |
+ |
+ char mime_type[512]; |
+ strncpy(mime_type, &resource[1], 511); |
+ mime_type[511] = '\0'; |
+ |
+ if (strcmp(request, "GET")) { |
+ printf("Unknown request: 'GET %s %s'\n", request, version); |
+ } else { |
+ printf("Requesting '%s'\n", mime_type); |
+ } |
+ |
+ // Keep reading until we encounter a blank line. |
+ // This will skip over the Host, Connection, User-Agent, ... |
+ char ignore[512] = "ignore"; |
+ while (strspn(ignore, " \n\r\t") != strlen(ignore)) { |
+ read_text_data(connection, ignore, sizeof(ignore)); |
+ } |
+ |
+ // At this point, a normal webserver would verify that the requested |
+ // resource exists and then return it with the appropriate mimetype. |
+ |
+ // However, we return empty content, but with the requested plugin mimetype. |
+ write_data(connection, "HTTP/1.0 200 OK\r\n"); |
+ write_data(connection, "Content-Type: "); |
+ write_data(connection, mime_type); |
+ write_data(connection, "\r\n\r\n"); |
+ |
+ // This dummy data is unused, but must be present or else the reader may hang. |
+ write_data(connection, "Data\n"); |
+} |
+ |
+int main(int argc, char *argv[]) { |
+ printf("Chromoting client webserver: http://localhost:%d\n", PORT); |
+ |
+ signal(SIGCHLD, SIG_IGN); |
+ |
+ // Create socket. |
+ int sock = socket(AF_INET, SOCK_STREAM, 0); |
+ if (sock < 0) { |
+ error("Unable to open socket"); |
+ } |
+ |
+ // Initialize socket address struct. |
+ struct sockaddr_in serv_addr; |
+ bzero((char*)&serv_addr, sizeof(serv_addr)); |
+ serv_addr.sin_family = AF_INET; |
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
+ serv_addr.sin_port = htons(PORT); |
+ |
+ // Bind socket. |
+ if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { |
+ error("Unable to bind socket"); |
+ } |
+ |
+ if (listen(sock, 5) < 0) { |
+ error("Unable to listen to socket"); |
+ } |
+ |
+ while (1) { |
+ int connection = accept(sock, NULL, NULL); |
+ if (connection < 0) { |
+ error("Unable to accept connection"); |
+ } |
+ |
+ pid_t pid = fork(); |
+ if (pid == 0) { |
+ // Child process. |
+ if (close(sock) < 0) { |
+ error("Unable to close socket in child"); |
+ } |
+ |
+ // Handle the request. |
+ handle_request(connection); |
+ |
+ // Success. Exit to kill child process. |
+ exit(0); |
+ } else { |
+ // Parent process. |
+ if (close(connection) < 0) { |
+ error("Unable to close connection in parent"); |
+ } |
+ } |
+ } |
+ |
+ return 0; |
+} |
Property changes on: remoting/tools/client_webserver/main.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |