Created
July 7, 2010 16:30
-
-
Save dyoder/466918 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A simple store using libmicrohttp */ | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <stdarg.h> | |
#include <sys/socket.h> | |
#include <microhttpd.h> | |
#include <string.h> | |
#include <fcntl.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
/* URL processing */ | |
const char * | |
validate_url (const char *url) | |
{ | |
/* URLs must not have any slashes, that's our rule */ | |
return index(url + 1, '/') ? 0 : url + 1; | |
} | |
/* Accept all connections */ | |
int | |
accept_policy (void *cls, const struct sockaddr *addr, socklen_t addrlen) | |
{ | |
return 1; | |
} | |
/* Queue a simple response */ | |
int | |
queue_response (struct MHD_Connection *connection, unsigned int code, char *msg) | |
{ | |
return MHD_queue_response (connection, code, | |
MHD_create_response_from_data (strlen (msg), | |
msg, 0, 0)); | |
} | |
/* Callback for GET to read the next chunk of the file */ | |
int | |
get_reader (void *cls, uint64_t pos, char *buf, int max) | |
{ | |
int *fd = cls; | |
int nread; | |
nread = read (*fd, buf, max); | |
if (nread == 0) /* EOF becomes termination code */ | |
nread = -1; | |
return nread; | |
} | |
/* release resources from GET */ | |
void | |
cleanup_reader (void *cls) | |
{ | |
int *fd = cls; | |
close (*fd); | |
free (fd); | |
} | |
/* GET just fetches the file */ | |
int | |
dispatch_get (struct MHD_Connection *connection, const char *url) | |
{ | |
int fd, *cls; | |
fd = open (url, O_RDONLY, 0); | |
if (fd < 0) | |
return queue_response (connection, MHD_HTTP_NOT_FOUND, | |
"Resource not found"); | |
cls = malloc (sizeof *cls); | |
*cls = fd; | |
return MHD_queue_response (connection, MHD_HTTP_OK, | |
MHD_create_response_from_callback | |
(MHD_SIZE_UNKNOWN,1024, get_reader, cls, | |
cleanup_reader)); | |
} | |
struct upload_closure | |
{ | |
struct MHD_Response *response; | |
int fd; | |
}; | |
/* uploading for PUT and POST */ | |
int | |
continue_upload (struct MHD_Connection *connection, | |
const char *upload_data, size_t *upload_data_size, | |
struct upload_closure *c) | |
{ | |
int nwritten; | |
nwritten = write (c->fd, upload_data, *upload_data_size); | |
if (nwritten < 0) | |
return 0; | |
else | |
{ | |
*upload_data_size -= nwritten; | |
return 1; | |
} | |
} | |
int | |
begin_upload (struct MHD_Connection *connection, int fd, | |
const char *upload_data, size_t *upload_data_size, | |
void **con_cls) | |
{ | |
struct upload_closure *c; | |
c = malloc (sizeof *c); | |
if (c) | |
{ | |
char *msg = "Upload successful"; | |
c->response = MHD_create_response_from_data (strlen (msg), msg, 0, 0); | |
c->fd = fd; | |
*con_cls = c; | |
return 1; | |
} | |
else | |
return 0; | |
} | |
void | |
completion_callback (void *cls, | |
struct MHD_Connection *connection, | |
void **con_cls, | |
enum MHD_RequestTerminationCode toe) | |
{ | |
struct upload_closure *c = *con_cls; | |
if (c) | |
{ | |
close (c->fd); | |
if (c->response) | |
MHD_destroy_response (c->response); | |
free (c); | |
} | |
} | |
/* POST handling */ | |
void | |
add_post_location_header (struct MHD_Connection *connection, | |
struct upload_closure *c, | |
char *name) | |
{ | |
const char *host; | |
char *newurl; | |
host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Host"); | |
newurl = alloca (strlen (host) + 100); | |
sprintf (newurl, "http://%s/%s", host, name); | |
MHD_add_response_header (c->response, "Location", newurl); | |
} | |
int | |
dispatch_post (struct MHD_Connection *connection, const char *url, | |
const char *upload_data, size_t *upload_data_size, | |
void **con_cls) | |
{ | |
int fd; | |
struct upload_closure *c = *con_cls; | |
char name[7]; | |
if (*url) | |
return queue_response (connection, MHD_HTTP_NOT_FOUND, | |
"Improper POST name"); | |
if (c) | |
{ | |
if (*upload_data_size) | |
return continue_upload (connection, upload_data, upload_data_size, c); | |
else | |
if (MHD_queue_response (connection, MHD_HTTP_CREATED, c->response)) | |
{ | |
c->response = 0; | |
return 1; | |
} | |
else | |
return 0; | |
} | |
else | |
{ | |
strcpy (name, "XXXXXX"); | |
fd = mkstemp (name); | |
if (fd < 0) | |
return queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, | |
"Cannot create new resource"); | |
else | |
{ | |
if (begin_upload (connection, fd, | |
upload_data, upload_data_size, con_cls)) | |
{ | |
add_post_location_header (connection, *con_cls, name); | |
return 1; | |
} | |
else | |
return 0; | |
} | |
} | |
} | |
int | |
dispatch_put (struct MHD_Connection *connection, const char *url, | |
const char *upload_data, size_t *upload_data_size, | |
void **con_cls) | |
{ | |
int fd; | |
struct upload_closure *c = *con_cls; | |
if (c) | |
{ | |
if (*upload_data_size) | |
return continue_upload (connection, upload_data, upload_data_size, c); | |
else | |
if (MHD_queue_response (connection, MHD_HTTP_OK, c->response)) | |
{ | |
c->response = 0; | |
return 1; | |
} | |
else | |
return 0; | |
} | |
else | |
{ | |
fd = open (url, O_WRONLY|O_TRUNC, 0666); | |
if (fd < 0) | |
return queue_response (connection, MHD_HTTP_NOT_FOUND, | |
"Resource not found"); | |
else | |
return begin_upload (connection, fd, upload_data, upload_data_size, | |
con_cls); | |
} | |
} | |
/* Access handler */ | |
int | |
access_handler (void *cls, struct MHD_Connection *connection, | |
const char *url, const char *method, const char *version, | |
const char *upload_data, size_t *upload_data_size, | |
void **con_cls) | |
{ | |
url = validate_url (url); | |
if (!url) | |
return queue_response (connection, MHD_HTTP_NOT_FOUND, | |
"Improper resource name"); | |
/* Dispatch based on method */ | |
if (!strcmp ("GET", method)) | |
return dispatch_get (connection, url); | |
else if (!strcmp ("PUT", method)) | |
return dispatch_put (connection, url, | |
upload_data, upload_data_size, con_cls); | |
else if (!strcmp ("POST", method)) | |
return dispatch_post (connection, url, | |
upload_data, upload_data_size, con_cls); | |
else | |
return queue_response (connection, MHD_HTTP_NOT_IMPLEMENTED, | |
"Method not understood"); | |
} | |
/* Main program */ | |
main (int argc, char *argv) | |
{ | |
struct MHD_Daemon *daemon; | |
daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY, | |
2020, | |
accept_policy, 0, | |
access_handler, 0, | |
MHD_OPTION_NOTIFY_COMPLETED, | |
completion_callback, 0, | |
MHD_OPTION_END); | |
if (daemon) | |
pause (); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment