Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Add fastCGI support please #88

Closed
NobodyXu opened this issue Dec 28, 2020 · 9 comments
Closed

Feature request: Add fastCGI support please #88

NobodyXu opened this issue Dec 28, 2020 · 9 comments
Labels
feature Code based project improvement

Comments

@NobodyXu
Copy link

NobodyXu commented Dec 28, 2020

Most people building websites nowadays use nginx or appache to reverse proxy the real dynamic content server instead of directly expose the underlying server directly as

  • nobody would expose their underlying server directly to outside world, as they would like find CVE in their underlying server or their server would be under attack by hackers.
    The http/https code in nginx and appache are much more battle tested and has less bug.
  • people who really needs to use C++ to write their dynamic content server would probably also use distributed computing and fastCGI is a more efficient protocol to use than http or https
  • performance of https in nginx and appache is probably much better than crow
  • developers are familiar with nginx and appache and know how to tune them. Some might even has special patch applied to them for their own use case
  • Separating https server and content server enables them to run at different privileges:
    The https server could run as root while the content server can run as a normal user.
    Any bug in content server won't cause privilege escalation or crash in https server and the user won't feel the crash of content server as the server can be restarted in background without the https connection being closed.

There are broader audience who needs fastCGI in their content server.

While nginx and appache can also proxy http, it is slower than fastCGI as

  • http is a text based protocol while fastCGI is a binary one
  • fastCGI support multiplexing while http does not
  • fastCGI support unix socket for proxying local server while http does not

and nobody in their right mind would proxy their underlying content server over https as it is too heavy weight.
The right solution here is fastCGI. It is designed for this kind of application, so the experience programming with fastCGI is probably better than http.

Thus I think crow should have fastCGI support as it is extremely important.

I found archive of the specification of fastCGI here and it also has a reference implementation of fastCGI library fcgi2.

There are also kcgi and fastcgipp that are C and C++ server that supports fastCGI.

@NobodyXu NobodyXu changed the title Feature: Add fastCGI support please Feature request: Add fastCGI support please Dec 28, 2020
@NobodyXu
Copy link
Author

I personally hope you guys can prioritize this over https support since fastCGI is more important in real world.

It is also much simpler to implement fastCGI compared to https.

@The-EDev
Copy link
Member

Thanks for the suggestion and the information. Your main criticism seems to be against 2 things:

  1. Not using a proxy
  2. Using an HTTP / HTTPS proxy
    Your solution is to use FastCGI.

As far as the criticisms are concerned, We do not expect people to run Crow directly or proxy over HTTPS Even in the original repository's issues, it is mentioned that you should use a proxy and that you probably should not proxy over https.

As for using FastCGI to solve these concerns, this is where I start to disagree.

The primary comparison here is proxying over FastCGI vs HTTP/1.1

You mention that FastCGI is binary as opposed to text and supports multiplexing, which is similar to HTTP/2, and carries the same concerns that:

  • Binary protocols aren't much faster than text based ones simply because the binary vs text difference only occurs in the headers, not the request / response bodies
  • I'm also not sure how much the advantages of FastCGI are when the request is originally made to Nginx or Apache via HTTP, I would assume there would either be no difference or less overhead associated with http requests considering the server application wouldn't need to translate to a different protocol, although I'm not sure about that.
  • The main valid part is using Unix domain sockets as opposed to TCP sockets. I've not benchmarked them, but generally it is assumed that Unix domain sockets are faster, so this would be the only valid advantage in my opinion.

Other points to consider regarding FastCGI is that:

  • It requires a new set of dependencies and systems that are completely missing from Crow.
  • It veers too far off the path of the original design.
  • Unlike HTTP/2, I don't even know where to begin to try and understand let alone implement FastCGI.

All of that makes something like FastCGI a very had sell, let alone giving it priority over features that help complete or simplify the process of working with crow.

I like systems that run fast and efficient, but I'm not gonna lie to you. At the moment FastCGI is further down the list than HTTP/2, which I've been delaying since I started working on Crow.

There is already a PR (ipkn#379) That adds a simple form of Unix Domain Socket support to Crow. If you'd like to add FastCGI implementation yourself. I suggest you start there. I will also look into it, but once more I cannot spare much time trying to implement it, especially given how difficult it is to find people or time to work on Crow.

Thank you once more for the informative issue, and the suggestion.

@The-EDev The-EDev added the feature Code based project improvement label Dec 28, 2020
@NobodyXu
Copy link
Author

After looking into the source for a little, I think it is understandable that you didn't prioritize this since the entire structure of crow is designed around http and it might be even quite difficult to add https support to crow.

I would look into fastCGI myself and see if I can help.

@NobodyXu
Copy link
Author

NobodyXu commented Dec 28, 2020

@The-EDev
Luckly, I do find a fastCGI library fastcgipp writen in C++ and it also has an example file echo.cpp.

I also checked fastCGI spec and IMHO the header is actually quite simple:

typedef struct {
    unsigned char version;
    unsigned char type;
    Big_endian_uint16_t requestId;
    Big_endian_uint16_t contentLength;
    unsigned char paddingLength;
    unsigned char reserved;
    unsigned char contentData[contentLength];
    unsigned char paddingData[paddingLength];
} FCGI_Record;

However, it does make me suspect whether fastCGI is worth it, as it is so simple and still sends information like hostname, cookies, uri via text.

It does save parsing 'name=val' by sending structure like

struct {
    nameLength; // might be 1 byte or 4 bytes
    valueLength; // same as above
    unsigned char name[];
    unsigned char value[];
}

but that doesn't make a lot of difference and might even make performance worse since it needs to also send FCGI_BeginRequestBody and FCGI_EndRequestBody.

The only benefit from fastCGI as far as I seen is the multiplexing and pretty much anything else doesn't have any real benefit for the content server.

But even multiplexing might not have any real benefits since in real world, the network between the reverse proxy and the content server are pretty good and having multiple TCP connection really isn't a big problem.

It seems that fastCGI is exactly as what it is advertised: a replacement for CGI and isn't of much benefit to crow just like what you thought @The-EDev .

@NobodyXu
Copy link
Author

I guess the only way to make crow much faster than now is to link with nginx and act like a builtin module to it, let nginx handle all the tcp connection/http parsing and shares the same address space.

This would make crow enjoy the performance of nginx while getting mature http/http2.0 or even http3.0 for free.

@The-EDev
Copy link
Member

@NobodyXu I did think of that, I'm not sure how Nginx and Apache modules work, but I believe flask does something similar using Werkzeug, only thing is how do you link the 2 (Crow and the server program), but if that approach works it'll be very beneficial.

@NobodyXu
Copy link
Author

NobodyXu commented Dec 28, 2020

I just took a look at one of the modules listed on nginx’s wiki: mod_zip, and found information on installation in README.markdown:

Installation

To install, compile nginx with the following option:

--add-module=/path/to/mod_zip
nginx 1.10.0 or later is required
(optional) to enable the X-Archive-Charset header, libiconv is required
http_postpone must be enabled by including at least one of the http_addition, http_slice or http_ssi modules

I also found config, which is probably important for the building of the module.

Upon further investigation of its ngx_http_zip_module.c, I was able to identify the necessary data structure for a module:

ngx_module_t  ngx_http_zip_module = {
    NGX_MODULE_V1,
    &ngx_http_zip_module_ctx,   /* module context */
    NULL,                       /* module directives */
    NGX_HTTP_MODULE,            /* module type */
    NULL,                       /* init master */
    NULL,                       /* init module */
    NULL,                       /* init process */
    NULL,                       /* init thread */
    NULL,                       /* exit thread */
    NULL,                       /* exit process */
    NULL,                       /* exit master */
    NGX_MODULE_V1_PADDING
};

@NobodyXu
Copy link
Author

@NobodyXu I did think of that, I'm not sure how Nginx and Apache modules work, but I believe flask does something similar using Werkzeug, only thing is how do you link the 2 (Crow and the server program), but if that approach works it'll be very beneficial.

It seems that the module can either be loaded dynamically or statically as addon:

if [ $ngx_module_link = DYNAMIC ] ; then
    ngx_module_name=ngx_http_zip_module
    ngx_module_srcs="$ngx_addon_dir/ngx_http_zip_module.c $ngx_addon_dir/ngx_http_zip_parsers.c $ngx_addon_dir/ngx_http_zip_file.c $ngx_addon_dir/ngx_http_zip_headers.c"

    . auto/module
elif [ $ngx_module_link = ADDON ] ; then
    HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_zip_module"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_zip_module.c"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_zip_parsers.c"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_zip_file.c"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_zip_headers.c"

    . auto/module    
fi

The code above is taken from config.

@The-EDev
Copy link
Member

The-EDev commented Jan 3, 2021

The discussion here can continue at #94

@The-EDev The-EDev closed this as completed Jan 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Code based project improvement
Projects
None yet
Development

No branches or pull requests

2 participants