diff options
| -rw-r--r-- | examples/append.c | 25 | ||||
| -rw-r--r-- | examples/cookie.c | 37 | ||||
| -rw-r--r-- | examples/echo.c | 69 | ||||
| -rw-r--r-- | examples/fcgi.c | 6 | ||||
| -rw-r--r-- | examples/upload.c | 53 | ||||
| -rw-r--r-- | src/cgi.c | 38 | ||||
| -rw-r--r-- | src/cgi.h | 15 | ||||
| -rw-r--r-- | src/cookie.h | 34 | ||||
| -rw-r--r-- | src/cookies.h | 10 | ||||
| -rw-r--r-- | src/error.h | 6 | ||||
| -rw-r--r-- | src/file.h | 25 | ||||
| -rw-r--r-- | src/inner_cookies.c (renamed from src/cookies.c) | 2 | ||||
| -rw-r--r-- | src/inner_cookies.h | 10 | ||||
| -rw-r--r-- | src/inner_multipart.c (renamed from src/multipart.c) | 2 | ||||
| -rw-r--r-- | src/inner_multipart.h | 13 | ||||
| -rw-r--r-- | src/inner_urlencoded.c | 144 | ||||
| -rw-r--r-- | src/inner_urlencoded.h | 13 | ||||
| -rw-r--r-- | src/magi.h | 16 | ||||
| -rw-r--r-- | src/multipart.h | 13 | ||||
| -rw-r--r-- | src/param.h | 24 | ||||
| -rw-r--r-- | src/request.h | 102 | ||||
| -rw-r--r-- | src/response.c | 64 | ||||
| -rw-r--r-- | src/response.h | 47 | ||||
| -rw-r--r-- | src/urlenc.c | 135 | ||||
| -rw-r--r-- | src/urlenc.h | 13 | 
25 files changed, 475 insertions, 441 deletions
| diff --git a/examples/append.c b/examples/append.c index cb49e50..702f0fb 100644 --- a/examples/append.c +++ b/examples/append.c @@ -1,22 +1,18 @@ -#include <cgi.h> -#include <request.h> -#include <response.h> +#include <magi.h>  #include <stdio.h>  #include <stdlib.h> -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res)  { -    char * data = magi_param_list_get(req->params, "addon"); +    char *data = magi_param_list_get(req->params, "addon");      if (data) { -        FILE * file = fopen("file_to_append", "a"); +        FILE *file = fopen("file_to_append", "a");          fputs(data, file);          fclose(file);      } -    magi_response_content_type(res, magi_xhtml); -    magi_response_add( -        res, +    magi_response_add(res,          "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' "          "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>"          "<html xmlns='http://www.w3.org/1999/xhtml'>" @@ -30,16 +26,15 @@ void response_request(struct magi_request * req, struct magi_response * res)          "</html>");  } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[])  { -    struct magi_request request; +    magi_request request;      magi_request_setup(&request); -    if (magi_request_cgi(&request) && magi_request_resume_cgi(&request)) { -        struct magi_response response; +    if (magi_request_full_cgi(&request)) { +        magi_response response;          magi_response_setup(&response);          response_request(&request, &response); -        magi_response_cgi(&response); -        magi_response_destroy(&response); +        magi_response_cgi_clear(&response);      } else {          magi_error_cgi(request.error);      } diff --git a/examples/cookie.c b/examples/cookie.c index bb1e1d1..365f989 100644 --- a/examples/cookie.c +++ b/examples/cookie.c @@ -1,26 +1,22 @@ -#include <cgi.h> -#include <cookie.h> -#include <request.h> -#include <response.h> +#include <magi.h>  #include <stdio.h>  #include <stdlib.h> -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res)  { -    struct magi_cookie_list * current; +    magi_cookie_list *current; -    magi_response_content_type(res, magi_xhtml); -    magi_response_add( -        res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " -             "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" -             "<html xmlns='http://www.w3.org/1999/xhtml'>" -             "<head><title>Cookie Listing and Setting</title></head>" -             "<body>"); +    magi_response_add(res, +        "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " +        "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" +        "<html xmlns='http://www.w3.org/1999/xhtml'>" +        "<head><title>Cookie Listing and Setting</title></head>" +        "<body>");      for (current = req->cookies; current; current = current->next) { -        magi_response_add_format(res, "[%s] = [%s]<br/>", current->item.name, -                                 current->item.data); +        magi_response_add_format(res, +            "[%s] = [%s]<br/>", current->item.name, current->item.data);      }      magi_response_add(res, "</body></html>"); @@ -28,16 +24,15 @@ void response_request(struct magi_request * req, struct magi_response * res)      magi_response_cookie_easy(res, "cookie", "monster");  } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[])  { -    struct magi_request request; +    magi_request request;      magi_request_setup(&request); -    if (magi_request_cgi(&request) && magi_request_resume_cgi(&request)) { -        struct magi_response response; +    if (magi_request_full_cgi(&request)) { +        magi_response response;          magi_response_setup(&response);          response_request(&request, &response); -        magi_response_cgi(&response); -        magi_response_destroy(&response); +        magi_response_cgi_clear(&response);      } else {          magi_error_cgi(request.error);      } diff --git a/examples/echo.c b/examples/echo.c index e9807f0..81bdcf4 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -1,16 +1,10 @@ -#include <cgi.h> -#include <cookie.h> -#include <param.h> -#include <request.h> -#include <response.h> +#include <magi.h>  #include <stdio.h>  #include <stdlib.h> -void proceed_cookies(struct magi_cookie_list * cookies, -                     struct magi_response *    response) +void proceed_cookies(magi_cookie_list *cookies, magi_response *response)  { -    magi_response_add(response, "<h2>Cookies:</h2>");      while (cookies) {          magi_response_add(response, "Cookie with name [");          magi_response_add(response, cookies->item.name); @@ -33,36 +27,30 @@ void proceed_cookies(struct magi_cookie_list * cookies,          magi_response_add(response, "]<br/>");          cookies = cookies->next;      } -    magi_response_add(response, "<hr/>");  } -void proceed_params(struct magi_param_list * params, -                    struct magi_response *   response) +void proceed_params(magi_param_list *params, magi_response *response)  {      while (params) { -        magi_response_add_format(response, "[%s] is [%s]<br/>", -                                 params->item.name, params->item.data); +        magi_response_add_format(response, +            "[%s] is [%s]<br/>", params->item.name, params->item.data);          params = params->next;      } -    magi_response_add(response, "<hr/>");  } -void proceed_files(struct magi_file_list * files, -                   struct magi_response *  response) +void proceed_files(magi_file_list *files, magi_response *response)  {      while (files) { -        magi_response_add_format(response, "[%s] was [%s] on userside<br/>", -                                 files->item.param_name, -                                 files->item.file_name); +        magi_file f = files->item; +        magi_response_add_format(response, +            "[%s] was [%s] on userside<br/>", f.param_name, f.file_name);          files = files->next;      } -    magi_response_add(response, "<hr/>");  } -void process_meta(struct magi_request * req, struct magi_response * res) +void process_meta(magi_request *req, magi_response *res)  { -    magi_response_add(res, -                      "<h1>Echo CGI Script</h1>I was called with method ["); +    magi_response_add(res, "I was called with method [");      magi_response_add(res, req->method);      if (req->uri) {          magi_response_add(res, "] with URL ["); @@ -87,38 +75,45 @@ void process_meta(struct magi_request * req, struct magi_response * res)      magi_response_add(res, "]<br/>");  } -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res)  { -    magi_response_content_type(res, magi_xhtml); -    magi_response_add( -        res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " -             "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" -             "<html xmlns='http://www.w3.org/1999/xhtml'>" -             "<head><title>Echo</title></head>" -             "<body>"); +    magi_response_add(res, +        "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " +        "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" +        "<html xmlns='http://www.w3.org/1999/xhtml'>" +        "<head><title>Echo</title></head>" +        "<body>"); + +    magi_response_add(res, "<h1>Echo CGI Script</h1>");      process_meta(req, res); + +    magi_response_add(res, "<h2>Cookies:</h2>");      proceed_cookies(req->cookies, res); +      magi_response_add(res, "<h2>Parameters:</h2>");      proceed_params(req->params, res); +      magi_response_add(res, "<h2>URL Parameters:</h2>");      proceed_params(req->url_params, res); +      magi_response_add(res, "<h2>HTTP Parameters:</h2>");      proceed_params(req->http_params, res); +      magi_response_add(res, "<h2>Files:</h2>");      proceed_files(req->files, res); +      magi_response_add(res, "</body></html>");  } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[])  { -    struct magi_request request; +    magi_request request;      magi_request_setup(&request); -    if (magi_request_cgi(&request) && magi_request_resume_cgi(&request)) { -        struct magi_response response; +    if (magi_request_full_cgi(&request)) { +        magi_response response;          magi_response_setup(&response);          response_request(&request, &response); -        magi_response_cgi(&response); -        magi_response_destroy(&response); +        magi_response_cgi_clear(&response);      } else {          magi_error_cgi(request.error);      } diff --git a/examples/fcgi.c b/examples/fcgi.c index 2790f9d..bb5645e 100644 --- a/examples/fcgi.c +++ b/examples/fcgi.c @@ -1,7 +1,5 @@ -#include <error.h> -#include <fastcgi.h> -#include <request.h> -#include <response.h> +/* * * TODO * * */ +#include <magi.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> diff --git a/examples/upload.c b/examples/upload.c index 1947f93..6a3a7a4 100644 --- a/examples/upload.c +++ b/examples/upload.c @@ -1,50 +1,45 @@ -#include <cgi.h> -#include <multipart.h> -#include <request.h> -#include <response.h> +#include <magi.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res)  { -    char *             name = magi_param_list_get(req->params, "name"); -    struct magi_file * data = magi_file_list_get(req->files, "data"); +    char      *name = magi_param_list_get(req->params, "name"); +    magi_file *data = magi_file_list_get(req->files, "data");      if (name && data) {          rename("data", name);      } -    magi_response_content_type(res, magi_xhtml); -    magi_response_add( -        res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " -             "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" -             "<html xmlns='http://www.w3.org/1999/xhtml'>" -             "<head><title>Upload File</title></head>" -             "<body>" -             "<form action='/cgi-bin/upload' method='post' " -             "enctype='multipart/form-data'><fieldset>" -             "<input type='text' name='name' value='filename'/>" -             "<input type='file' name='data'/>" -             "<input type='submit' value='Upload'/>" -             "</fieldset></form>" -             "</body>" -             "</html>"); +    magi_response_add(res, +        "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " +        "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" +        "<html xmlns='http://www.w3.org/1999/xhtml'>" +        "<head><title>Upload File</title></head>" +        "<body>" +        "<form action='/cgi-bin/upload' method='post' " +        "enctype='multipart/form-data'><fieldset>" +        "<input type='text' name='name' value='filename'/>" +        "<input type='file' name='data'/>" +        "<input type='submit' value='Upload'/>" +        "</fieldset></form>" +        "</body>" +        "</html>");  } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[])  { -    struct magi_request   request; -    struct magi_tempfiles tmps = { 0, 0, 0, 0 }; +    magi_request   request; +    magi_tempfiles tmps = { 0, 0 };      magi_request_setup(&request);      magi_tempfiles_add(&tmps, "data", "data", 0);      magi_request_setup_tempfiles(&request, &tmps); -    if (magi_request_cgi(&request) && magi_request_resume_cgi(&request)) { -        struct magi_response response; +    if (magi_request_full_cgi(&request)) { +        magi_response response;          magi_response_setup(&response);          response_request(&request, &response); -        magi_response_cgi(&response); -        magi_response_destroy(&response); +        magi_response_cgi_clear(&response);      } else {          magi_error_cgi(request.error);      } @@ -1,14 +1,14 @@  #include "cgi.h"  #include "cookie.h" -#include "cookies.h"  #include "error.h"  #include "file.h" -#include "multipart.h" +#include "inner_cookies.h" +#include "inner_multipart.h" +#include "inner_tools.h" +#include "inner_urlencoded.h"  #include "param.h"  #include "request.h" -#include "urlenc.h" -#include "utils.h"  #include <ctype.h>  #include <stdio.h>  #include <stdlib.h> @@ -132,7 +132,7 @@ static void cgi_url(struct magi_request * request)      char * in = 0;      cgi_input_get(&request->error, &in, request->url_params_max);      if (!request->error) { -        magi_urlenc(&request->url_params, request, in); +        magi_urlencoded(&request->url_params, request, in);      }      free(in);  } @@ -218,7 +218,7 @@ int magi_request_resume_cgi(struct magi_request * request)              char * in = 0;              cgi_input_post(e, &in, request->params_max);              if (!*e) { -                magi_urlenc(&request->params, request, in); +                magi_urlencoded(&request->params, request, in);              }              free(in);          } else { @@ -229,6 +229,11 @@ int magi_request_resume_cgi(struct magi_request * request)      return !request->error;  } +int magi_request_full_cgi(magi_request *request) +{ +    return magi_request_cgi(request) && magi_request_resume_cgi(request); +} +  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *   * CGI Response @@ -268,6 +273,7 @@ void output_cookies(struct magi_cookie_list * list)      }  } +  int magi_response_cgi(struct magi_response * response)  {      output_http_params(response->http_params); @@ -278,14 +284,20 @@ int magi_response_cgi(struct magi_response * response)      return 1;  } +int magi_response_cgi_clear(magi_response *response) +{ +    int ok = magi_response_cgi(response); +    magi_response_destroy(response); +    return ok; +} + +  int magi_error_cgi(enum magi_error error)  {      struct magi_response res;      magi_response_setup(&res);      magi_response_http(&res, "Status", "400 Bad Request"); -    magi_response_content_type(&res, magi_xhtml); -    magi_response_add_format( -        &res, +    magi_response_add_format(&res,          "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' "          "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>"          "<html xmlns='http://www.w3.org/1999/xhtml'>" @@ -296,11 +308,5 @@ int magi_error_cgi(enum magi_error error)          "</body>"          "</html>",          magi_error_message(error)); -    if (magi_response_cgi(&res)) { -        magi_response_destroy(&res); -        return 1; -    } else { -        magi_response_destroy(&res); -        return 0; -    } +    return magi_response_cgi_clear(&res);  } @@ -8,20 +8,27 @@  /* Constructs non-post part of request from environment;   * Returns null only in case of error. */ -int magi_request_cgi(struct magi_request * request); +int magi_request_cgi(magi_request *request);  /* Complete request with post data from standard input;   * Returns null only in case of error. */ -int magi_request_resume_cgi(struct magi_request * request); +int magi_request_resume_cgi(magi_request *request); + +/* Shortcut for applying both previous. */ +int magi_request_full_cgi(magi_request *request);  /* Sends response to standard output;   * Returns null only in case of error. */ -int magi_response_cgi(struct magi_response * response); +int magi_response_cgi(magi_response *response); + +/* Shortcut for magi_response_cgi with desctruction after it. */ +int magi_response_cgi_clear(magi_response *response); +  /* Sends a standart response of Bad Request error to standard output;   * Returns null only in case of error. */ -int magi_error_cgi(enum magi_error error); +int magi_error_cgi(magi_error error);  #endif diff --git a/src/cookie.h b/src/cookie.h index 82c914e..7eb3e9d 100644 --- a/src/cookie.h +++ b/src/cookie.h @@ -2,31 +2,31 @@  #define MAGI_INCLUDED_COOKIE -struct magi_cookie { +typedef struct magi_cookie {      /* All pointers must be valid as 'free' arguments. */ -    char * name; -    char * data; -    char * path; -    char * domain; -    char * port; -}; +    char *name; +    char *data; +    char *path;    /* Without '/' at the end. */ +    char *domain;  /* With dot at the begining. */ +    char *max_age; /* In seconds until discard, used only in response. */ +} magi_cookie; -struct magi_cookie_list { -    struct magi_cookie_list * next; /* Must be valid as 'free' arguments. */ -    struct magi_cookie        item; -}; +typedef struct magi_cookie_list { +    struct magi_cookie_list *next; /* Must be valid as 'free' arguments. */ +    magi_cookie              item; +} magi_cookie_list;  /* Addition of item to top of list. Null <=> error. */ -int magi_cookie_list_add(struct magi_cookie_list ** list, -                         struct magi_cookie *       item); +int magi_cookie_list_add(magi_cookie_list **list, magi_cookie *item); -/* First node in list: node.name == name; else null. */ -struct magi_cookie * magi_cookie_list_get(struct magi_cookie_list * list, -                                          const char *              name); +/* Data of last cookie in list: cookie.name == name, returns null if no such; + * Last cookie in list is first from request, and from RFC 2109 we know that + * first cookie is the most accurate for request's domain and path. */ +char *magi_cookie_list_get(magi_cookie_list *list, const char *name);  /* Freeing and invalidation of list. */ -void magi_cookie_list_destroy(struct magi_cookie_list * list); +void magi_cookie_list_destroy(magi_cookie_list *list);  #endif diff --git a/src/cookies.h b/src/cookies.h deleted file mode 100644 index 98b2ada..0000000 --- a/src/cookies.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MAGI_INCLUDED_COOKIES -#define MAGI_INCLUDED_COOKIES - -#include "request.h" - - -void magi_cookies(struct magi_request * request, const char * data); - - -#endif diff --git a/src/error.h b/src/error.h index f8f0aed..4a91962 100644 --- a/src/error.h +++ b/src/error.h @@ -2,7 +2,7 @@  #define MAGI_INCLUDED_ERROR -enum magi_error { +typedef enum magi_error {      magi_error_none = 0,      magi_error_nobound,      magi_error_unknown, @@ -13,9 +13,9 @@ enum magi_error {      magi_error_urlenc,      magi_error_multipart,      magi_error_limit -}; +} magi_error; -const char * magi_error_message(enum magi_error error); +const char *magi_error_message(magi_error error);  #endif @@ -4,28 +4,27 @@  #include "param.h" -struct magi_file { +typedef struct magi_file {      /* All pointers must be valid as 'free' arguments. */ -    char *                   param_name; /* Name of corresponding form field */ -    char *                   file_name;  /* File name on user's computer */ -    struct magi_param_list * params;     /* Multipart params (e.g. type) */ -}; +    char            *param_name; /* Name of corresponding form field */ +    char            *file_name;  /* File name on user's computer */ +    magi_param_list *params;     /* Multipart params (e.g. type) */ +} magi_file; -struct magi_file_list { -    struct magi_file_list * next; /* Must be valid as 'free' argument. */ -    struct magi_file        item; -}; +typedef struct magi_file_list { +    struct magi_file_list *next; /* Must be valid as 'free' argument. */ +    magi_file              item; +} magi_file_list;  /* Addition of item to top of list. Null <=> error. */ -int magi_file_list_add(struct magi_file_list ** list, struct magi_file * item); +int magi_file_list_add(magi_file_list **list, magi_file *item);  /* First node in list: node.param_name == name; else null. */ -struct magi_file * magi_file_list_get(struct magi_file_list * list, -                                      const char *            name); +magi_file *magi_file_list_get(magi_file_list *list, const char *name);  /* Freeing and invalidation of list. */ -void magi_file_list_destroy(struct magi_file_list * list); +void magi_file_list_destroy(magi_file_list *list);  #endif diff --git a/src/cookies.c b/src/inner_cookies.c index 4cbe659..d9035c4 100644 --- a/src/cookies.c +++ b/src/inner_cookies.c @@ -1,5 +1,5 @@  /* * *   TODO   * * */ -#include "cookies.h" +#include "inner_cookies.h"  #include "utils.h"  #include <stdlib.h> diff --git a/src/inner_cookies.h b/src/inner_cookies.h new file mode 100644 index 0000000..c336cf7 --- /dev/null +++ b/src/inner_cookies.h @@ -0,0 +1,10 @@ +#ifndef MAGI_INCLUDED_INNER_COOKIES +#define MAGI_INCLUDED_INNER_COOKIES + +#include "request.h" + + +void magi_cookies(magi_request *request, const char *data); + + +#endif diff --git a/src/multipart.c b/src/inner_multipart.c index 7b829d8..65252e5 100644 --- a/src/multipart.c +++ b/src/inner_multipart.c @@ -1,5 +1,5 @@  /* Support for multifile controls are not provided. */ -#include "multipart.h" +#include "inner_multipart.h"  #include "error.h"  #include "param.h" diff --git a/src/inner_multipart.h b/src/inner_multipart.h new file mode 100644 index 0000000..c3f7b65 --- /dev/null +++ b/src/inner_multipart.h @@ -0,0 +1,13 @@ +#ifndef MAGI_INCLUDED_INNER_MULTIPART +#define MAGI_INCLUDED_INNER_MULTIPART + +#include "request.h" + + +void magi_multipart(magi_request *request, +                    char         *boundary, +                    int         (*next)(void *userdata), +                    void         *next_userdata); + + +#endif diff --git a/src/inner_urlencoded.c b/src/inner_urlencoded.c new file mode 100644 index 0000000..e3ea56a --- /dev/null +++ b/src/inner_urlencoded.c @@ -0,0 +1,144 @@ +#include "inner_urlencoded.h" + +#include "inner_tools.h" +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local Shortcuts + */ +/* Call only if is_hex(c). */ +static int from_hex(char c) +{ +    if (isdigit(c)) { +        return c - '0'; +    } else { +        return toupper(c) - 'A' + 10; +    } +} + +static int is_hex(char c) +{ +    return isdigit(c) || strchr("ABCDEF", toupper(c)); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * URL Decoding + */ +static int deurl(char ** data) +{ +    char * val = *data; +    int    ti; +    int    ci; +    if (!val) { +        *data  = malloc(1); +        **data = 0; +        return 1; +    } +    for (ti = 0, ci = 0; val[ci]; ++ti, ++ci) { +        if (val[ci] == '%') { +            if (is_hex(val[ci + 1]) && is_hex(val[ci + 2])) { +                /* Since chars can be signed, arithmetics are not safe. */ +                val[ti] = from_hex(val[ci + 2]);       /* 0000xxxx */ +                val[ti] |= from_hex(val[ci + 1]) << 4; /* XXXXxxxx */ +                ci += 2; /* Two extra characters are readed from code. */ +            } else { +                return 0; +            } +        } else if (val[ci] == '+') { +            val[ti] = ' '; +        } else { +            val[ti] = val[ci]; +        } +    } +    val[ti] = 0; +    return 1; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Urlencoded Automata + */ +enum st { st_error = 0, st_name, st_data }; + +struct automata { +    struct magi_param_list ** list; +    struct magi_param         param; +    int                       size; +    int                       len; +}; + + +static enum st parse_name(struct automata * a, char c) +{ +    if (c == '&' || c == ';') { /* Impossible character means error. */ +        return st_error; +    } +    if (c == '=') { /* Separator ends name. */ +        a->size = 1; +        a->len  = 0; +        return st_data; +    } + +    if (!magi_str_add(&a->param.name, &a->len, &a->size, c)) { +        return st_error; +    } +    return st_name; +} + +static enum st end_data(struct automata * a) +{ +    if (deurl(&a->param.name) && deurl(&a->param.data)) { +        if (magi_param_list_add(a->list, &a->param)) { +            a->size       = 1; +            a->len        = 0; +            a->param.name = 0; +            a->param.data = 0; +            return st_name; +        } +    } +    return st_error; +} + +static enum st parse_data(struct automata * a, char c) +{ +    if (c == '=') { /* Impossible character means error. */ +        return st_error; +    } +    if (c == '&' || c == ';') { /* Separator ends data. */ +        return end_data(a); +    } + +    if (!magi_str_add(&a->param.data, &a->len, &a->size, c)) { +        return st_error; +    } +    return st_data; +} + +void magi_urlencoded(struct magi_param_list ** list, +                     struct magi_request *     request, +                     const char *              encoded) +{ +    enum st         state; +    struct automata a = { 0, { 0, 0 }, 1, 0 }; +    a.list            = list; +    *list             = 0; +    if (!encoded || !*encoded) { +        return; +    } +    for (state = st_name; state && *encoded; ++encoded) { +        if (state == st_name) { +            state = parse_name(&a, *encoded); +        } else { +            state = parse_data(&a, *encoded); +        } +    } +    if (state == st_name || !state || !end_data(&a)) { +        free(a.param.name); +        free(a.param.data); +        request->error = magi_error_urlenc; +    } +} diff --git a/src/inner_urlencoded.h b/src/inner_urlencoded.h new file mode 100644 index 0000000..e07ed6f --- /dev/null +++ b/src/inner_urlencoded.h @@ -0,0 +1,13 @@ +#ifndef MAGI_INCLUDED_INNER_URLENCODED +#define MAGI_INCLUDED_INNER_URLENCODED + +#include "request.h" + + +/* Fills request->url_params via parsing encoded data. */ +void magi_urlencoded(magi_param_list **list, +                     magi_request     *request, +                     const char       *encoded); + + +#endif diff --git a/src/magi.h b/src/magi.h new file mode 100644 index 0000000..b7df63c --- /dev/null +++ b/src/magi.h @@ -0,0 +1,16 @@ +#ifndef MAGI_INCLUDED +#define MAGI_INCLUDED +/*     Magi Header Collection + * You can include this, if you don't want to think about headers. + */ +#include "cgi.h" +#include "cookie.h" +#include "error.h" +#include "fastcgi.h" +#include "file.h" +#include "param.h" +#include "request.h" +#include "response.h" +#include "urlenc.h" + +#endif diff --git a/src/multipart.h b/src/multipart.h deleted file mode 100644 index 47cfefe..0000000 --- a/src/multipart.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef MAGI_INCLUDED_MULTIPART -#define MAGI_INCLUDED_MULTIPART - -#include "request.h" - - -void magi_multipart(struct magi_request * request, -                    char *                boundary, -                    int (*next)(void * userdata), -                    void * next_userdata); - - -#endif diff --git a/src/param.h b/src/param.h index 3f8cefe..bebacd7 100644 --- a/src/param.h +++ b/src/param.h @@ -2,27 +2,27 @@  #define MAGI_INCLUDED_PARAM -struct magi_param { +typedef struct magi_param {      /* All pointers must be valid as 'free' arguments. */ -    char * name; -    char * data; -}; +    char *name; +    char *data; +} magi_param; -struct magi_param_list { -    struct magi_param_list * next; /* Must be valid as 'free' argument. */ -    struct magi_param        item; -}; +typedef struct magi_param_list { +    struct magi_param_list *next; /* Must be valid as 'free' argument. */ +    magi_param              item; +} magi_param_list;  /* Addition of item to top of list. Null <=> error. */ -int magi_param_list_add(struct magi_param_list ** list, -                        struct magi_param *       item); +int magi_param_list_add(magi_param_list **list, +                        magi_param       *item);  /* Data of the first node in list: node.name == name; else null. */ -char * magi_param_list_get(struct magi_param_list * list, const char * name); +char *magi_param_list_get(magi_param_list *list, const char *name);  /* Freeing and invalidation of list. */ -void magi_param_list_destroy(struct magi_param_list * list); +void magi_param_list_destroy(magi_param_list *list);  #endif diff --git a/src/request.h b/src/request.h index be92370..ffa239f 100644 --- a/src/request.h +++ b/src/request.h @@ -27,75 +27,91 @@   * document_uri: {script_name}{path_info}   *                /bin/script  /article/magic   */ -struct magi_request { +typedef struct magi_request {      /* * * Results * * */      /* All pointers of this section must be valid as 'free' arguments. */      /* Parsed */ -    struct magi_cookie_list * cookies; -    struct magi_param_list *  http_params; /* HTTP Header parameters */ -    struct magi_param_list *  url_params;  /* Urlencoded paramteres from URL */ -    struct magi_param_list *  params;      /* Parameters from 'post' body */ -    struct magi_file_list *   files;       /* 'Post' multipart files */ +    magi_cookie_list *cookies; +    magi_param_list  *http_params; /* HTTP Header parameters */ +    magi_param_list  *url_params;  /* Paramteres from URL */ +    magi_param_list  *params;      /* Parameters from 'post' body */ +    magi_file_list   *files;       /* 'Post' multipart files */      /* Environment Shortcuts */ -    char * method;          /* REQUEST_METHOD */ -    char * uri;             /* REQUEST_URI */ -    char * document_root;   /* DOCUMENT_ROOT */ -    char * document_uri;    /* DOCUMENT_URI */ -    char * script_name;     /* SCRIPT_NAME */ -    char * script_filename; /* SCRIPT_FILENAME */ -    char * remote_addr;     /* REMOTE_ADDR */ -    char * remote_port;     /* REMOTE_PORT */ -    char * server_addr;     /* SERVER_ADDR */ -    char * server_name;     /* SERVER_NAME */ +    char *method;          /* REQUEST_METHOD */ +    char *uri;             /* REQUEST_URI */ +    char *document_root;   /* DOCUMENT_ROOT */ +    char *document_uri;    /* DOCUMENT_URI */ +    char *script_name;     /* SCRIPT_NAME */ +    char *script_filename; /* SCRIPT_FILENAME */ +    char *remote_addr;     /* REMOTE_ADDR */ +    char *remote_port;     /* REMOTE_PORT */ +    char *server_addr;     /* SERVER_ADDR */ +    char *server_name;     /* SERVER_NAME */      /* server_name can be not a domain name, even if request is done with it.       * (Use http_params["HTTP_HOST"] instead.) */ -    char * server_port;     /* SERVER_PORT */ -    char * server_protocol; /* SERVER_PROTOCOL */ -    char * server_software; /* SERVER_COFTWARE */ -    char * path_info;       /* PATH_INFO */ +    char *server_port;     /* SERVER_PORT */ +    char *server_protocol; /* SERVER_PROTOCOL */ +    char *server_software; /* SERVER_COFTWARE */ +    char *path_info;       /* PATH_INFO */      /* Request Error Code */ -    enum magi_error error; +    magi_error error;      /* * * Settings * * */      /* Callback for processing files */ -    void (*file_callback)(struct magi_file * file, -                          char *             addon, -                          int                addon_len, -                          int                is_addon_last, -                          void *             userdata); -    void * file_callback_userdata; -    int    file_callback_addon_max; +    void (*file_callback)(magi_file *file, +                          char      *addon, +                          int        addon_len, +                          int        is_addon_last, +                          void      *userdata); +    void *file_callback_userdata; +    int   file_callback_addon_max;      /* Limits for memory used (null <=> unlimitted) */      int cookies_max;      int url_params_max;      int http_params_max;      int params_max; -}; +} magi_request;  /* Setup request with default settings. */ -void magi_request_setup(struct magi_request * request); - -struct magi_tempfiles { -    int           count; -    const char ** param_names; -    const char ** locations; -    int *         maximums; /* Null maximums[i] <=> unlimited tempfiles[i]. */ -}; -void magi_tempfiles_add(struct magi_tempfiles * tmps, -                        const char *            name, -                        const char *            path, -                        int                     max); +void magi_request_setup(magi_request *request); + + +/* Destroys request. */ +void magi_request_destroy(magi_request *request); + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Tempfiles Callback + */ +typedef struct magi_tempfile { +    const char *param_name; /* Form field name, in which file is expected. */ +    const char *location;   /* Location to load file in. */ +    int         maximum;    /* Null <=> unlimited. */ +} magi_tempfile; + +typedef struct magi_tempfiles { +    int            count; +    magi_tempfile *tmps; +} magi_tempfiles; + +void magi_tempfiles_add(magi_tempfiles *tmps, +                        const char     *name, +                        const char     *path, +                        int             max); + +void magi_tempfiles_destroy(magi_tempfiles *tmps); +  /* Setup request callback with files loaded into corresponding to their   * parameter names locations; paths are in magi_tempfiles struct. */ -void magi_request_setup_tempfiles(struct magi_request *   request, -                                  struct magi_tempfiles * table); +void magi_request_setup_tempfiles(magi_request   *request, +                                  magi_tempfiles *table);  /* Destroys request. */  void magi_request_destroy(struct magi_request * request); diff --git a/src/response.c b/src/response.c index 7e2ec0b..e4cd342 100644 --- a/src/response.c +++ b/src/response.c @@ -6,33 +6,33 @@  #include <stdlib.h>  #include <string.h> -int vsnprintf(char * s, size_t n, const char * format, va_list arg); +/* TODO: realise vsnprintf or eliminate need of it. (see musl) */ +int vsnprintf(char *s, size_t n, const char *format, va_list arg); -void magi_response_setup(struct magi_response * response) +void magi_response_setup(magi_response *response)  {      response->cookies      = 0;      response->http_params  = 0;      response->content_type = 0; +    magi_response_content_type(response, "application/xhtml+xml");      response->content      = magi_str_create(0);      response->len          = 0;      response->size         = 1;  } - -void magi_response_content_type(struct magi_response * response, -                                enum magi_content_type type) +void magi_response_content_type(magi_response *response, const char *type)  { -    const char * const messages[] = { -        "Content-Type: application/xhtml+xml", /* magi_xhtml */ -    }; -    if (!response->content_type) { -        const char * end       = messages[type] + strlen(messages[type]); -        response->content_type = magi_str_create_copy(messages[type], end); -    } +    static const char *const ct    = "Content-Type: "; +    static const int         ctlen = 15; +    const int                len   = strlen(type); +    free(response->content_type); +    response->content_type = malloc(ctlen + len + 1); +    memcpy(response->content_type, ct, ctlen); +    memcpy(response->content_type + ctlen, type, len + 1);  } -void magi_response_add(struct magi_response * r, const char * addon) +void magi_response_add(magi_response *r, const char *addon)  {      int addon_len;      if (!addon) { @@ -46,11 +46,9 @@ void magi_response_add(struct magi_response * r, const char * addon)      r->len += addon_len;  } -void magi_response_add_format(struct magi_response * response, -                              const char *           addon, -                              ...) +void magi_response_add_format(magi_response *response, const char *addon, ...)  { -    char *  act_addon; +    char   *act_addon;      int     n;      va_list args;      va_start(args, addon); @@ -66,34 +64,36 @@ void magi_response_add_format(struct magi_response * response,      }  } -void magi_response_cookie(struct magi_response * response, -                          struct magi_cookie *   cookie) +void magi_response_cookie(magi_response *response, magi_cookie *cookie)  {      magi_cookie_list_add(&response->cookies, cookie);  } -void magi_response_cookie_easy(struct magi_response * response, -                               const char *           name, -                               const char *           value) +void magi_response_cookie_easy(magi_response *response, +                               const char    *name, +                               const char    *value) +{ + +void magi_response_cookie_discard(magi_response *response, const char *name)  { -    struct magi_cookie cookie = { 0, 0, 0, 0, 0 }; -    cookie.name = magi_str_create_copy(name, name + strlen(name)); -    cookie.data = magi_str_create_copy(value, value + strlen(value)); +    magi_cookie cookie = { 0, 0, 0, 0, 0 }; +    cookie.name        = magi_str_create_copy(name, strlen(name)); +    cookie.max_age     = magi_str_create(1); +    cookie.max_age[0]  = '0';      magi_cookie_list_add(&response->cookies, &cookie);  } -void magi_response_http(struct magi_response * response, -                        const char *           name, -                        const char *           data) +void magi_response_http(magi_response *response, +                        const char    *name,  { -    struct magi_param param = { 0, 0 }; -    param.name              = magi_str_create_copy(name, name + strlen(name)); -    param.data              = magi_str_create_copy(data, data + strlen(data)); +    magi_param param = { 0, 0 }; +    param.name       = magi_str_create_copy(name, strlen(name)); +    param.data       = magi_str_create_copy(data, strlen(data));      magi_param_list_add(&response->http_params, ¶m);  } -void magi_response_destroy(struct magi_response * response) +void magi_response_destroy(magi_response *response)  {      if (!response) {          return; diff --git a/src/response.h b/src/response.h index 95f6537..a51d4a4 100644 --- a/src/response.h +++ b/src/response.h @@ -5,42 +5,39 @@  #include "param.h" -enum magi_content_type { magi_xhtml = 0 }; +typedef struct magi_response { +    magi_cookie_list *cookies; +    magi_param_list  *http_params; +    char             *content_type; +    char             *content; +    int               len; +    int               size; +} magi_response; -struct magi_response { -    struct magi_cookie_list * cookies; -    struct magi_param_list *  http_params; -    char *                    content_type; -    char *                    content; -    int                       len; -    int                       size; -}; +void magi_response_setup(magi_response *response); -void magi_response_setup(struct magi_response * response); +void magi_response_content_type(magi_response *response, const char *type); -void magi_response_content_type(struct magi_response * response, -                                enum magi_content_type type); +void magi_response_add(magi_response *response, const char *addon); +void magi_response_add_format(magi_response *response, const char *addon, ...); -void magi_response_add(struct magi_response * response, const char * addon); -void magi_response_add_format(struct magi_response * response, -                              const char *           addon, -                              ...); +void magi_response_cookie(magi_response *response, magi_cookie *cookie); -void magi_response_cookie(struct magi_response * response, -                          struct magi_cookie *   cookie); +void magi_response_cookie_easy(magi_response *response, +                               const char    *name, +                               const char    *value); -void magi_response_cookie_easy(struct magi_response * response, -                               const char *           name, -                               const char *           value); +void magi_response_cookie_discard(magi_response *response, +                                  const char    *name); -void magi_response_http(struct magi_response * response, -                        const char *           name, -                        const char *           data); +void magi_response_http(magi_response *response, +                        const char    *name, +                        const char    *data); -void magi_response_destroy(struct magi_response * response); +void magi_response_destroy(magi_response *response);  #endif diff --git a/src/urlenc.c b/src/urlenc.c index 8c38a0a..bb0bada 100644 --- a/src/urlenc.c +++ b/src/urlenc.c @@ -2,23 +2,12 @@  #include "utils.h"  #include <ctype.h> -#include <stdlib.h>  #include <string.h>  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *   * Local Shortcuts   */ -/* Call only if is_hex(c). */ -static int from_hex(char c) -{ -    if (isdigit(c)) { -        return c - '0'; -    } else { -        return toupper(c) - 'A' + 10; -    } -} -  /* Call only if 0 <= num && num <= 15. */  static char to_hex(int num)  { @@ -26,11 +15,6 @@ static char to_hex(int num)      return hex[num];  } -static int is_hex(char c) -{ -    return isdigit(c) || strchr("ABCDEF", toupper(c)); -} -  static int is_url(char c)  {      return isalnum(c) || strchr("$-_.+ !*'(),", c); @@ -38,125 +22,6 @@ static int is_url(char c)  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * URL Decoding - */ -static int deurl(char ** data) -{ -    char * val = *data; -    int    ti; -    int    ci; -    if (!val) { -        *data  = malloc(1); -        **data = 0; -        return 1; -    } -    for (ti = 0, ci = 0; val[ci]; ++ti, ++ci) { -        if (val[ci] == '%') { -            if (is_hex(val[ci + 1]) && is_hex(val[ci + 2])) { -                /* Since chars can be signed, arithmetics are not safe. */ -                val[ti] = from_hex(val[ci + 2]);       /* 0000xxxx */ -                val[ti] |= from_hex(val[ci + 1]) << 4; /* XXXXxxxx */ -                ci += 2; /* Two extra characters are readed from code. */ -            } else { -                return 0; -            } -        } else if (val[ci] == '+') { -            val[ti] = ' '; -        } else { -            val[ti] = val[ci]; -        } -    } -    val[ti] = 0; -    return 1; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Urlencoded Automata - */ -enum st { st_error = 0, st_name, st_data }; - -struct automata { -    struct magi_param_list ** list; -    struct magi_param         param; -    int                       size; -    int                       len; -}; - - -static enum st parse_name(struct automata * a, char c) -{ -    if (c == '&' || c == ';') { /* Impossible character means error. */ -        return st_error; -    } -    if (c == '=') { /* Separator ends name. */ -        a->size = 1; -        a->len  = 0; -        return st_data; -    } - -    if (!magi_str_add(&a->param.name, &a->len, &a->size, c)) { -        return st_error; -    } -    return st_name; -} - -static enum st end_data(struct automata * a) -{ -    if (deurl(&a->param.name) && deurl(&a->param.data)) { -        if (magi_param_list_add(a->list, &a->param)) { -            a->size       = 1; -            a->len        = 0; -            a->param.name = 0; -            a->param.data = 0; -            return st_name; -        } -    } -    return st_error; -} - -static enum st parse_data(struct automata * a, char c) -{ -    if (c == '=') { /* Impossible character means error. */ -        return st_error; -    } -    if (c == '&' || c == ';') { /* Separator ends data. */ -        return end_data(a); -    } - -    if (!magi_str_add(&a->param.data, &a->len, &a->size, c)) { -        return st_error; -    } -    return st_data; -} - -void magi_urlenc(struct magi_param_list ** list, -                 struct magi_request *     request, -                 const char *              encoded) -{ -    enum st         state; -    struct automata a = { 0, { 0, 0 }, 1, 0 }; -    a.list            = list; -    *list             = 0; -    if (!encoded || !*encoded) { -        return; -    } -    for (state = st_name; state && *encoded; ++encoded) { -        if (state == st_name) { -            state = parse_name(&a, *encoded); -        } else { -            state = parse_data(&a, *encoded); -        } -    } -    if (state == st_name || !state || !end_data(&a)) { -        free(a.param.name); -        free(a.param.data); -        request->error = magi_error_urlenc; -    } -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *   * URL Encoding   */  int magi_urlenc_size(const char * plain) diff --git a/src/urlenc.h b/src/urlenc.h index 5240109..edaec08 100644 --- a/src/urlenc.h +++ b/src/urlenc.h @@ -1,17 +1,10 @@  #ifndef MAGI_INCLUDED_URLENC  #define MAGI_INCLUDED_URLENC -#include "request.h" - -/* Fills request->url_params via parsing encoded data. */ -void magi_urlenc(struct magi_param_list ** list, -                 struct magi_request *     request, -                 const char *              encoded); - -/* 'code' from urlencode must have size of at least magi_urlenc_size(plain). */ -int  magi_urlenc_size(const char * plain); -void magi_urlencode(const char * plain, char * code); +/* 'code' from urlenc must have size of at least magi_urlenc_size(plain). */ +int  magi_urlenc_size(const char *plain); +void magi_urlenc(const char *plain, char *code);  #endif | 
