![]() |
install | documentation | examples | articles | changelog 16.6.0 released on Mar 08, 2023 | articles updated on Mar 20, 2023
|
int vv_fc_request (vv_fc *req);
All input and output parameters are contained in a single variable of type "vv_fc", the pointer to which is passed to "vv_fc_request()" function that runs a server request. This also has the advantage of forward compatibility because any future changes are contained in this type, and is also simple to use.// Define and initialize request variable
vv_fc req = {0};
// You could also do:
// memset ((char*)&req, 0, sizeof(vv_fc));
...
int result = vv_fc_request (&req);
- Return valuetypedef struct {
const char *fcgi_server; // the IP:port/socket_path to server
const char *req_method; // request method
const char *app_path; // application path
const char *req; // request name
const char *url_payload; // URL payload (path+query string)
const char *content_type; // content type
int content_len; // content len
const char *req_body; // request body (i.e. content)
char **env; // environment to pass into request on server side
int timeout; // timeout for request
int req_status; // status of request from server
char *data; // actual response from server
int data_len; // length of response from server
char *error; // error message from server
int error_len; // length of error from server
// other elements used internally by Vely client
vv_fc_out_hook out_hook; // hook to get output data as soon as it arrives
vv_fc_err_hook err_hook; // hook get error data as soon as it arrives
} vv_fc;
Here is the more detailed explanation:char *env[5];
env[0] = "REMOTE_USER";
env[1] = "John"
env[2] = "MY_VARIABLE";
env[3] = "8000"
env[4] = NULL;
Thus, if you are passing N environment variables to the server, you must size "env" as "char*" array with 2*N+1 elements.// Declare and initialize request variable
vv_fc req = {0};
// Setup the req variable
...
// Execute request
vv_fc_request (&req);
// Free request output (data and error streams)
free (req.data);
free (req.error);
If you do not free the results of a request, your program may experience a memory leak. If your program exits right after issuing any request(s), you may skip freeing results as that is automatically done on exit by the Operating System. If you wish to save the results of multiple executions and process them later as a group, you can omit freeing them and save "req.data" (and/or "req.error") in some kind of an array for later processing; this way you do not have to copy the results unnecessarily.typedef void (*vv_fc_out_hook)(char *recv, int recv_len);
To specify a hook for error data (i.e. from stderr), you must write a C function with the following signature:typedef void (*vv_fc_err_hook)(char *recv, int recv_len);
"recv" is the data received and "recv_len" is its length. To register these functions with "vv_fc_request()" function, assign their pointers to "out_hook" and "err_hook" members of request variable of type "vv_fc". Note that the output hook (i.e. hook function of type "vv_fc_out_hook") will receive empty string ("") in "recv" and "recv_len" will be 0 when the request has completed, meaning all data (including error) has been received.// Output hook
void get_output(char *d, int l)
{
printf("Got output of [%.*s] of length [%d]", l, d, l);
}
// Error hook
void get_err(char *d, int l)
{
printf("Got error of [%.*s] of length [%d]", l, d, l);
}
...
vv_fc req = {0};
...
// Register output and error hooks
req.out_hook = &get_out;
req.err_hook = &get_err;
#include "vfcgi.h"
void main ()
{
// Request type vv_fc - create a request variable and zero it out
vv_fc req = {0};
req.fcgi_server = "/var/lib/vv/helloworld/sock/sock"; // Unix socket
req.req_method = "GET"; // GET HTTP method
req.app_path = "/helloworld"; // application path
req.req = "/hello-simple"; // request name
// Make a request
int res = vv_fc_request (&req);
// Check return status, and if there's an error, display error code and the
// corresponding error message. Otherwise, print out server response.
if (res != VV_OKAY) printf ("Request failed [%d] [%s]\n", res, req.errm);
else printf ("%s", req.data);
// Free up resources so there are no memory leaks
free (req.data);
free (req.error);
}
To make this client application:In this case, you're using a Unix socket to communicate with the FastCGI server. To test with a Vely request handler, copy the following code to "hello_simple.vely" file:gcc -o cli cli.c -g $(vv -i)
#include "vely.h"
void hello_simple()
{
silent-header
out-header default
@Hi there!
}
Create and make the Vely server application and run it via local Unix socket:Run the FastCGI client:sudo vf -i -u $(whoami) helloworld vv -q vf -m quit helloworld vf -w 1 helloworld
The output is, as expected:./cli
Hi there!
#include "vfcgi.h"
void main ()
{
// Request type vv_fc - create a request variable
vv_fc req;
// Add 3 environment variables (in the form of name, value, name, value, ... , NULL)
char *env[] = { "REMOTE_USER", "John", "SOME_VAR", "SOME\nVALUE", "NEW_VAR", "1000", NULL };
// Create a request
// Environment variables to pass to server request
req.env = env;
// Server IP and port
req.fcgi_server = "127.0.0.1:2301";
// Request method
req.req_method = "GET";
// Application path
req.app_path = "/helloworld";
// Request
req.req = "/hello";
// URL payload (path and query string)
req.url_payload = ""par1=val1&par2=91"";
// Content type
req.content_type = "application/json";
// Content (i.e. request body)
req.req_body = "This is request body";
// Content length
req.content_len = strlen (req.req_body);
// No timeout (set to 0)
req.timeout = 0;
// Make a request
int res = vv_fc_request (&req);
// Check return status, and if there's an error, display error code and the
// corresponding error message
if (res != VV_OKAY) printf("Request failed [%d] [%s]\n", res, req.errm);
else {
// If successful, display request results
// Exit code from the server processing
printf("Server status %d\n", req.req_status);
// Length of reply from server
printf("Len of data %d\n", req.data_len);
// Length of any error from server
printf("Len of error %d\n", req.error_len);
// Reply from server
printf("Data [%s]\n", req.data);
// Any error message from server
printf("Error [%s]\n", req.error);
}
// Free up resources so there are no memory leaks
free (req.data);
free (req.error);
}
To make this client application:To test it, you can create a Vely server application. Copy this to "hello.vely" file in a separate directory:gcc -o cli1 cli1.c -g $(vv -i)
#include "vely.h"
void hello()
{
silent-header
out-header default
// Get request body
request-body rb
// Get environment variables passed on from the client
get-sys web-environment "REMOTE_USER" to define ruser
get-sys web-environment "SOME_VAR" to define somev
get-sys web-environment "NEW_VAR" to define newv
// Output, print the environment variables, the PID of server process and the request body received from the client
@Hello World! [<<p-out ruser>>] [<<p-out somev>>] [<<p-out newv>>] [<<p-out newv>>] [<<p-out par1>>] <<pf-out "%d", getpid()>> <<p-out rb>>
// Output back a number of lines, generally as "Output line #<num of line>"
// After line #1418, print out "Line 1419 has an error" to stderr
// After line #4418, report an error and exit
// This demostrates outputting data to both stdout and stderr
num i;
for (i = 0; i < 8000; i++) {
@Output line #<<p-num i>>
if (i == 1419) {
pf-out to-error "Line %lld has an error\n", i
}
if (i == 4419) {
// Exit code of the server execution
exit-code 82
report-error "%s", "Some error!"
}
}
}
Create and make the Vely server application and run it on local TCP port 2301 to match the client above:Run the FastCGI client:sudo vf -i -u $(whoami) helloworld vv -q vf -m quit helloworld vf -w 1 -p 2301 helloworld
The output:./cli1
The output shows server exit code (82, see exit-code in the Vely code above), length of output data, the output data which includes environment variables passed to the server from client, the PID of server process, the request body from the client, and then the error output. Note that the data output (stdout) and the error output (stderr) are separated, since FastCGI protocol does use separate streams over the same connection. This makes working with the output easy, while the data transfer is fast at the same time.Server status 82 Len of data 78517 Len of error 35 Data [Hello World! [John] [SOME VALUE] [val1] [91] [1000] 11187 This is request body Output line #0 Output line #1 Output line #2 Output line #3 Output line #4 Output line #5 Output line #6 Output line #7 ... Output line #4413 Output line #4414 Output line #4415 Output line #4416 Output line #4417 Output line #4418 Output line #4419 ] Error [Line 1419 has an error Some error! ]