[RFC] Extend httpd.c to support REST services more easily

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[RFC] Extend httpd.c to support REST services more easily

tinic-lwip-devel
I present a patch which adds support for REST services over HTTP in a
relatively user 
friendly manner. 

Rationale: REST is the standard for most interesting Javascript
frameworks. 
My use case was a vue.js based configuration UI built into a STM32
microcontroller.

This is primarily a variation of the existing LWIP_HTTPD_SUPPORT_POST
code
but different enough to where extending or mashing it together was not
pratical. The two
new #ifdefs are LWIP_HTTPD_SUPPORT_REST and LWIP_HTTPD_REST_MANUAL_WND.
You either enable LWIP_HTTPD_SUPPORT_POST or LWIP_HTTPD_SUPPORT_REST but
not both.

My question is: Is there any interest in merging such functionality into
upstream LwIP?
If so I'd be willing to clean up and explain the code; add
documentation, examples and a
few test cases. On the other hand I am also happy to just move on :-)

My fork is here: https://github.com/tinic/lwip-ajax
A patch is attached to this email.

 From a user perspective a minimal REST service can be implemented as
such:

----
#define SERVICE_GET_STATUS 1
#define SERVICE_POST_SETTINGS 2

static int method = 0;

err_t httpd_rest_begin(void *handle, rest_method_t method, const char
*url, const char *, u16_t, int, u8_t *) {
    switch(method) {
        case REST_METHOD_GET: {
            if (strcmp(url, "/status") == 0) {
                method = SERVICE_GET_STATUS;
                return ERR_OK;
            }
        } break;

        case REST_METHOD_POST: {
            if (strcmp(url, "/settings") == 0) {
                method = SERVICE_POST_SETTINGS;
                return ERR_OK;
            }
        } break;

        case REST_METHOD_PUT:
        case REST_METHOD_PATCH:
        case REST_METHOD_DELETE:
        case REST_METHOD_OPTIONS: {
        } break;
    }
    method = 0;
    return ERR_ARG;
}


err_t httpd_rest_receive_data(void *handle, struct pbuf *p) {
    if (method == SERVICE_POST_SETTINGS) {
    
        // user: send data to json parser

        return ERR_OK;
    }
}

err_t httpd_rest_finished(void *handle, const char **data, u16_t
*dataLen) {
    if (method == SERVICE_POST_SETTINGS) {

        // Minimal set of fields for most browsers to work correctly in
2020
        // Response string is user controlled as it is security
sensitive
        const char *okResponse = 
            "HTTP/1.0 200 OK" CRLF
            "Access-Control-Allow-Origin: *" CRLF; // Wildcard is a
potential security risk

        *data = okResponse;
        *dataLen = strlen(okResponse);
        
        return ERR_OK;
    }

    if (method == SERVICE_GET_STATUS) {
        
        static char response[1024];        

        memset(response, 0, sizeof(response))
        
        // Minimal set of fields for most browsers to work correctly in
2020
        // Response string is user controlled as it is security
sensitive
        const char *responsePrototype = 
            "HTTP/1.0 200 OK" CRLF 
            "Access-Control-Allow-Origin: *" CRLF // Wildcard is a
potential security risk
            "Content-Type: application/json; charset=utf-8" CRLF 
            "X-Content-Type-Options: nosniff" CRLF
            "Vary: Origin, Accept-Encoding" CRLF
            "Content-Length: @@@@@@@@@@@" CRLF // Needs to be patched
after JSON data is added
            "Cache-Control: no-cache" CRLF
            CRLF;
            
        strncpy(response, responsePrototype, sizeof(response) - 1);
        
        // user: safely add json to response

        // user: safely patch content length field in response
        
        *data = response;
        *dataLen = strlen(response);

        return ERR_OK;
    }

    return ERR_ARG;
}
---

_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel

REST.patch (32K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Extend httpd.c to support REST services more easily

goldsimon@gmx.de
Am 29.10.2020 um 23:13 schrieb [hidden email]:

> I present a patch which adds support for REST services over HTTP in a
> relatively user 
> friendly manner. 
>
> Rationale: REST is the standard for most interesting Javascript
> frameworks. 
> My use case was a vue.js based configuration UI built into a STM32
> microcontroller.
>
> This is primarily a variation of the existing LWIP_HTTPD_SUPPORT_POST
> code
> but different enough to where extending or mashing it together was not
> pratical. The two
> new #ifdefs are LWIP_HTTPD_SUPPORT_REST and LWIP_HTTPD_REST_MANUAL_WND.
> You either enable LWIP_HTTPD_SUPPORT_POST or LWIP_HTTPD_SUPPORT_REST but
> not both.
>
> My question is: Is there any interest in merging such functionality into
> upstream LwIP?
> If so I'd be willing to clean up and explain the code; add
> documentation, examples and a
> few test cases. On the other hand I am also happy to just move on :-)

Being able to easily support REST would be nice, but I'm not sure if
there's enough man-power available for lwIP at the moment to integrate
this. A clean patch would of course help.

>
> My fork is here: https://github.com/tinic/lwip-ajax
> A patch is attached to this email.
>
>  From a user perspective a minimal REST service can be implemented as
> such:
>
> ----
> #define SERVICE_GET_STATUS 1
> #define SERVICE_POST_SETTINGS 2
>
> static int method = 0;

This won't work: you cannot use a global variable. REST calls may come
interleaved, depending on segment size. You have to pass everything as
arguments, not using globals.

>
> err_t httpd_rest_begin(void *handle, rest_method_t method, const char
> *url, const char *, u16_t, int, u8_t *) {

This won't work either: you have 2 variables named 'method' here.

Regards,
Simon

>     switch(method) {
>         case REST_METHOD_GET: {
>             if (strcmp(url, "/status") == 0) {
>                 method = SERVICE_GET_STATUS;
>                 return ERR_OK;
>             }
>         } break;
>
>         case REST_METHOD_POST: {
>             if (strcmp(url, "/settings") == 0) {
>                 method = SERVICE_POST_SETTINGS;
>                 return ERR_OK;
>             }
>         } break;
>
>         case REST_METHOD_PUT:
>         case REST_METHOD_PATCH:
>         case REST_METHOD_DELETE:
>         case REST_METHOD_OPTIONS: {
>         } break;
>     }
>     method = 0;
>     return ERR_ARG;
> }
>
>
> err_t httpd_rest_receive_data(void *handle, struct pbuf *p) {
>     if (method == SERVICE_POST_SETTINGS) {
>     
>         // user: send data to json parser
>
>         return ERR_OK;
>     }
> }
>
> err_t httpd_rest_finished(void *handle, const char **data, u16_t
> *dataLen) {
>     if (method == SERVICE_POST_SETTINGS) {
>
>         // Minimal set of fields for most browsers to work correctly in
> 2020
>         // Response string is user controlled as it is security
> sensitive
>         const char *okResponse = 
>             "HTTP/1.0 200 OK" CRLF
>             "Access-Control-Allow-Origin: *" CRLF; // Wildcard is a
> potential security risk
>
>         *data = okResponse;
>         *dataLen = strlen(okResponse);
>         
>         return ERR_OK;
>     }
>
>     if (method == SERVICE_GET_STATUS) {
>         
>         static char response[1024];        
>
>         memset(response, 0, sizeof(response))
>         
>         // Minimal set of fields for most browsers to work correctly in
> 2020
>         // Response string is user controlled as it is security
> sensitive
>         const char *responsePrototype = 
>             "HTTP/1.0 200 OK" CRLF 
>             "Access-Control-Allow-Origin: *" CRLF // Wildcard is a
> potential security risk
>             "Content-Type: application/json; charset=utf-8" CRLF 
>             "X-Content-Type-Options: nosniff" CRLF
>             "Vary: Origin, Accept-Encoding" CRLF
>             "Content-Length: @@@@@@@@@@@" CRLF // Needs to be patched
> after JSON data is added
>             "Cache-Control: no-cache" CRLF
>             CRLF;
>             
>         strncpy(response, responsePrototype, sizeof(response) - 1);
>         
>         // user: safely add json to response
>
>         // user: safely patch content length field in response
>         
>         *data = response;
>         *dataLen = strlen(response);
>
>         return ERR_OK;
>     }
>
>     return ERR_ARG;
> }
> ---

_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Extend httpd.c to support REST services more easily

tinic-lwip-devel
On 2020-10-30 00:14, [hidden email] wrote:
>
> Being able to easily support REST would be nice, but I'm not sure if
> there's enough man-power available for lwIP at the moment to integrate
> this. A clean patch would of course help.
>

No problem, I'll move on then. Thanks for the clarification.

--tinic

_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel