Welcome! Log In Create A New Profile

Advanced

Invoking external URL/WS/REST from a custom Nginx Module

Posted by lus71 
Invoking external URL/WS/REST from a custom Nginx Module
January 27, 2011 06:14AM
Hi to everybody,

First of all! Thanks for Nginx!

I'm Luca from Italy...trying to learn how to implement custom Nginx modules.

I'm implementing a custom access filter module to verify a Google reCAPTCHA challenge. Something like:

[code]
location /signup {
recaptcha on; (to activate filter)
recaptcha_private_key "your google recaptcha key";
proxy_pass http://backends
}
[/code]


I did all the work...now I'm in dubt about the HTTP Request to Google WS from an nginx module.
I'm using libCurl to perform the POST specified in docs ( http://code.google.com/apis/recaptcha/docs/verify.html )


[code]
static ngx_int_t
ngx_recaptcha_verify_response( ngx_http_request_t *r, ngx_str_t *challenge, ngx_str_t *response ) {
ngx_int_t rc;

u_char *last = NULL;

ngx_str_t chunk = ngx_null_string;

ngx_recaptcha_access_filter_loc_conf_t *lcf = NULL;

ngx_str_t response_enc = ngx_null_string;
ngx_str_t challenge_enc = ngx_null_string;
ngx_str_t remote_addr = ngx_null_string;
ngx_str_t post_data = ngx_null_string;

ngx_str_t privatekey_key = ngx_string("privatekey");
ngx_str_t challenge_key = ngx_string("challenge");
ngx_str_t response_key = ngx_string("response");
ngx_str_t remoteip_key = ngx_string("remoteip");

CURL *curl = NULL;
CURLcode res;


rc = ngx_recaptcha_get_ip_str( r, &remote_addr );
if ( rc != NGX_OK ) {
ngx_log_error( NGX_LOG_ERR, r->connection->log, 0, "while retrieving remote address" );
return NGX_ERROR;
}

ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "remote address: %s", remote_addr.data );

rc = ngx_recaptcha_url_encode( r->pool, challenge, &challenge_enc );
if ( rc != NGX_OK ) {
ngx_log_error( NGX_LOG_ERR , r->connection->log, 0, "while url encoding %s", challenge->data );
return NGX_ERROR;
}

rc = ngx_recaptcha_url_encode( r->pool, response, &response_enc );
if ( rc != NGX_OK ) {
ngx_log_error( NGX_LOG_ERR , r->connection->log, 0, "while url encoding %s", response->data );
return NGX_ERROR;
}


lcf = ngx_http_get_module_loc_conf( r, ngx_recaptcha_access_filter_module );

post_data.len = (privatekey_key.len + 1); // privatekey=
post_data.len += (lcf->private_key.len + 1); // XXXXX&
post_data.len += (challenge_key.len + 1); // challenge=
post_data.len += (challenge_enc.len + 1); // YYYYY&
post_data.len += (response_key.len + 1); // response=
post_data.len += (response_enc.len + 1); // ZZZZZ&
post_data.len += (remoteip_key.len + 1); // remoteip=
post_data.len += (remote_addr.len + 1); // WWWWW&

post_data.data = ngx_pcalloc( r->pool, post_data.len + 1 );
if ( post_data.data == NULL ) {
ngx_log_error( NGX_LOG_ERR , r->connection->log, 0, "while allocating memory for <post_data>" );
return NGX_ERROR;
}
last = ngx_copy( post_data.data, privatekey_key.data, privatekey_key.len );
last = ngx_copy( last, "=", 1 );
last = ngx_copy( last, lcf->private_key.data, lcf->private_key.len );

last = ngx_copy( last, "&", 1 );

last = ngx_copy( last, challenge_key.data, challenge_key.len );
last = ngx_copy( last, "=", 1 );
last = ngx_copy( last, challenge_enc.data, challenge_enc.len );

last = ngx_copy( last, "&", 1 );

last = ngx_copy( last, response_key.data, response_key.len );
last = ngx_copy( last, "=", 1 );
last = ngx_copy( last, response_enc.data, response_enc.len );

last = ngx_copy( last, "&", 1 );

last = ngx_copy( last, remoteip_key.data, remoteip_key.len );
last = ngx_copy( last, "=", 1 );
last = ngx_copy( last, remote_addr.data, remote_addr.len );

*last = (u_char)'\0';

ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "post_data = <%s>", post_data.data );

curl_global_init( CURL_GLOBAL_ALL );

curl = curl_easy_init();
// Should I use CURLOPT_TIMEOUT option ?
curl_easy_setopt( curl, CURLOPT_VERBOSE, 1 );
curl_easy_setopt( curl, CURLOPT_USERAGENT, r->headers_in.user_agent->value.data );
curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1 );

curl_easy_setopt( curl, CURLOPT_URL, lcf->verify_url.data );
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_memory_callback );
curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)&chunk );
curl_easy_setopt( curl, CURLOPT_POSTFIELDS, (void*)post_data.data );
curl_easy_setopt( curl, CURLOPT_POSTFIELDSIZE, post_data.len );

res = curl_easy_perform(curl);
if ( res != CURLE_OK ) {
ngx_log_error( NGX_LOG_ERR , r->connection->log, 0, "curl_easy_perform failed: %s", curl_easy_strerror(res) );
curl_easy_cleanup(curl);
return NGX_ERROR;
}

curl_easy_cleanup( curl );

if ( chunk.data ) {
//.TODO Check the Google reCaptcha response (true | false)
ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Google response: %s", chunk.data );
}

return NGX_OK;
}
[/code]


The module works! All goes fine...but I'd like to know if this is correct.
May I perform an Http Request within my module?

Thank you very much!

Luca
Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 162
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready