(root)/
glib-2.79.0/
gio/
tests/
httpd.c
       1  #include <gio/gio.h>
       2  #include <string.h>
       3  
       4  static int port = 8080;
       5  static char *root = NULL;
       6  static GOptionEntry cmd_entries[] = {
       7    {"port", 'p', 0, G_OPTION_ARG_INT, &port,
       8     "Local port to bind to", NULL},
       9    G_OPTION_ENTRY_NULL
      10  };
      11  
      12  static void
      13  send_error (GOutputStream *out,
      14  	    int error_code,
      15  	    const char *reason)
      16  {
      17    char *res;
      18  
      19    res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
      20  			 "<html><head><title>%d %s</title></head>"
      21  			 "<body>%s</body></html>",
      22  			 error_code, reason,
      23  			 error_code, reason,
      24  			 reason);
      25    g_output_stream_write_all (out, res, strlen (res), NULL, NULL, NULL);
      26    g_free (res);
      27  }
      28  
      29  static gboolean
      30  handler (GThreadedSocketService *service,
      31  	 GSocketConnection      *connection,
      32  	 GSocketListener        *listener,
      33  	 gpointer                user_data)
      34  {
      35    GOutputStream *out;
      36    GInputStream *in;
      37    GFileInputStream *file_in;
      38    GDataInputStream *data;
      39    char *line, *escaped, *tmp, *query, *unescaped, *path, *version;
      40    GFile *f;
      41    GError *error;
      42    GFileInfo *info;
      43    GString *s;
      44  
      45    in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
      46    out = g_io_stream_get_output_stream (G_IO_STREAM (connection));
      47  
      48    data = g_data_input_stream_new (in);
      49    /* Be tolerant of input */
      50    g_data_input_stream_set_newline_type (data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
      51  
      52    line = g_data_input_stream_read_line (data, NULL, NULL, NULL);
      53  
      54    if (line == NULL)
      55      {
      56        send_error (out, 400, "Invalid request");
      57        goto out;
      58      }
      59  
      60    if (!g_str_has_prefix (line, "GET "))
      61      {
      62        send_error (out, 501, "Only GET implemented");
      63        goto out;
      64      }
      65  
      66    escaped = line + 4; /* Skip "GET " */
      67  
      68    version = NULL;
      69    tmp = strchr (escaped, ' ');
      70    if (tmp == NULL)
      71      {
      72        send_error (out, 400, "Bad Request");
      73        goto out;
      74      }
      75    *tmp = 0;
      76  
      77    version = tmp + 1;
      78    if (!g_str_has_prefix (version, "HTTP/1."))
      79      {
      80        send_error(out, 505, "HTTP Version Not Supported");
      81        goto out;
      82      }
      83  
      84    query = strchr (escaped, '?');
      85    if (query != NULL)
      86      *query++ = 0;
      87  
      88    unescaped = g_uri_unescape_string (escaped, NULL);
      89    path = g_build_filename (root, unescaped, NULL);
      90    g_free (unescaped);
      91    f = g_file_new_for_path (path);
      92    g_free (path);
      93  
      94    error = NULL;
      95    file_in = g_file_read (f, NULL, &error);
      96    if (file_in == NULL)
      97      {
      98        send_error (out, 404, error->message);
      99        g_error_free (error);
     100        goto out;
     101      }
     102  
     103    s = g_string_new ("HTTP/1.0 200 OK\r\n");
     104    info = g_file_input_stream_query_info (file_in,
     105  					 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
     106  					 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
     107  					 NULL, NULL);
     108    if (info)
     109      {
     110        const char *content_type;
     111        char *mime_type;
     112  
     113        if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
     114  	g_string_append_printf (s, "Content-Length: %"G_GINT64_FORMAT"\r\n",
     115  				g_file_info_get_size (info));
     116        content_type = g_file_info_get_content_type (info);
     117        if (content_type)
     118  	{
     119  	  mime_type = g_content_type_get_mime_type (content_type);
     120  	  if (mime_type)
     121  	    {
     122  	      g_string_append_printf (s, "Content-Type: %s\r\n",
     123  				      mime_type);
     124  	      g_free (mime_type);
     125  	    }
     126  	}
     127      }
     128    g_string_append (s, "\r\n");
     129  
     130    if (g_output_stream_write_all (out,
     131  				 s->str, s->len,
     132  				 NULL, NULL, NULL))
     133      {
     134        g_output_stream_splice (out,
     135  			      G_INPUT_STREAM (file_in),
     136  			      0, NULL, NULL);
     137      }
     138    g_string_free (s, TRUE);
     139  
     140    g_input_stream_close (G_INPUT_STREAM (file_in), NULL, NULL);
     141    g_object_unref (file_in);
     142  
     143   out:
     144    g_object_unref (data);
     145  
     146    return TRUE;
     147  }
     148  
     149  int
     150  main (int argc, char *argv[])
     151  {
     152    GSocketService *service;
     153    GOptionContext *context;
     154    GError *error = NULL;
     155  
     156    context = g_option_context_new ("<http root dir> - Simple HTTP server");
     157    g_option_context_add_main_entries (context, cmd_entries, NULL);
     158    if (!g_option_context_parse (context, &argc, &argv, &error))
     159      {
     160        g_printerr ("%s: %s\n", argv[0], error->message);
     161        return 1;
     162      }
     163  
     164    if (argc != 2)
     165      {
     166        g_printerr ("Root directory not specified\n");
     167        return 1;
     168      }
     169  
     170    root = g_strdup (argv[1]);
     171  
     172    service = g_threaded_socket_service_new (10);
     173    if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service),
     174  					port,
     175  					NULL,
     176  					&error))
     177      {
     178        g_printerr ("%s: %s\n", argv[0], error->message);
     179        return 1;
     180      }
     181  
     182    g_print ("Http server listening on port %d\n", port);
     183  
     184    g_signal_connect (service, "run", G_CALLBACK (handler), NULL);
     185  
     186    g_main_loop_run (g_main_loop_new (NULL, FALSE));
     187    g_assert_not_reached ();
     188  }