How to use Mongoose(a http server) to serve different request? - c++

I am a newbie in http and I am using a embedded http server called mongoose.
Using a web root in ~/web_root, I would like to do :
if uri == "/hello"
show "hello world"
else
show the file in web_root like index.html
I tried to use mongoose like this
struct mg_server *server;
server = mg_create_server(p, HttpEventHandler);
mg_set_option(server, "document_root", "~/web_root");
mg_set_option(server, "listening_port", "8080");
for(;;)
mg_poll_server(server, 1000);
and this is HttpEvenHandler
int HttpEventHandler(struct mg_connection *conn, mg_event ev) {
if(ev == MG_AUTH)
return MG_TRUE;
else if(ev == MG_REQUEST) {
if(strcmp("/hello", conn->uri) == 0) {
mg_printf_data(conn, "%s\n", "hello world");
}
return MG_TRUE;
}
// I don't know what to write here
return MG_FALSE;
}

else if(ev == MG_REQUEST) {
if(strcmp("/hello", conn->uri) == 0) {
mg_printf_data(conn, "%s\n", "hello world");
return MG_TRUE;
}
return MG_FALSE; // Let Mongoose serve the request
}
Also, I don't think that is going to work:
mg_set_option(server, "document_root", "~/web_root");
Specify a full path, e.g. /home/joe/web_root.

Is that REALLY what you want to achieve?
The document states that you can configure what kind of URIs are recognized as CGI invocation by command line options like -cgi_pattern /cgi-bin/*.cgi.
Then you only need to put a CGI executable named hello which outputs "hello world" under ~/web_root and tell the Mongoose server to use it as the only possible CGI: -cgi_pattern /hello$ (I haven't tested it by myself, though)

Hm, it seems that mg_set_option() is nowhere to find any more (ver. 7.3).
The correct API call for setting the web root directory would be: mg_http_serve_dir( connection, http_event_object, options);
The last parameter "options" has a member mg_http_serve_opts::root_dir. That would be the way to specify the web root directory for serving.
From design point of view this recent approach is more flexible, allowing to serve different directories based on different endpoints.

Related

How to load files to local file system with vibed?

I need to send data from web-browser to local FS. For sending data I am using Vue-JS component
<file-upload class="my-file-uploader" name="myFile" id="myCustomId" action="/upload" multiple>Inside Slot Text</file-upload>
My server side based on vibed. But I can't find example how to save binary data to local FS.
router.any("/upload", &upload);
...
void upload(HTTPServerRequest req, HTTPServerResponse res)
{
}
It's seems that I should use HTTPServerRequest.files But I can't understand how to use it. User upload takes is multiple files.
You can find a lot of examples within the Vibe.d Github repository.
For example there's a small uploader.
router.post("/upload", &uploadFile);
...
void uploadFile(scope HTTPServerRequest req, scope HTTPServerResponse res)
{
auto pf = "file" in req.files;
enforce(pf !is null, "No file uploaded!");
try moveFile(pf.tempPath, Path(".") ~ pf.filename);
catch (Exception e) {
logWarn("Failed to move file to destination folder: %s", e.msg);
logInfo("Performing copy+delete instead.");
copyFile(pf.tempPath, Path(".") ~ pf.filename);
}
res.writeBody("File uploaded!", "text/plain");
}
I don't know much about Vue.js, but it seems they use file too.

Getting the "no type was found that matches the controller named" error message during Ajax Request

I've seen a lot of topics about this, but unfortunately I believe that each case is a different case (or most of them), and I really would love some experts opinion about my case in particular since I cannot make my code work even after reading through some of the other topics.
Situation: I am using an Ajax Request call in jQuery to a WebService method I have created in an WebApi project together with a MVC 4 Application.
My WebService controller class looks like the default, like this:
public class AdditionalInfoController : ApiController
{
//GET api/AdditionalInfo
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
//GET api/AdditionalInfo/5
public string Get(int id)
{
return "value";
}
//PUT api/AdditionalInfo/5
public void Put(int id)
{
string test = "";
}
}
My Ajax Request from jQuery looks like this:
function GetAdditionalInfo(obj)
{
var request = jQuery.ajax({
url: "/api/AdditionalInfo/Get",
type: "GET",
data: { id: obj.id },
datatype: "json",
async: false,
beforeSend: function () {
},
complete: function () {
}
})
.done(function (a,b,c) {
alert("Additional info was retrieved successfully!");
})
.fail(function (a,b,c) {
alert("An error happened while trying to get the additional info!");
});
}
My WebAPIConfig file looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
And last but not least, this is my problem: this error message keeps appearing when I browse the returned data variable in .fail and this is what is written:
"{
"Message":"No HTTP resource was found that matches the request URI 'http://localhost:59096/api/AdditionalInfo/Get?id=1'.",
"MessageDetail":"No type was found that matches the controller named 'AdditionalInfo'."
}"
I would really appreciate it if someone could help me as soon as possible. Thanks in advance!
Best regards,
Mad
Looking at the error looks like Web API is unable to find the controller 'type' AdditionalInfo. Web API uses assemblies resolver to scan through the assemblies and finds out the controller types. In your case for some reason its unable to find your 'AdditionalInfo' controller probably because it has some problem loading the assembly having this controller.
Try the following and see if there are any errors logged in your EventLog. If you notice any errors then probably you should check if your controllers are present in those assemblies.
Make the following change in Web.config to view errors in EventLog
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="myListener"
type="System.Diagnostics.EventLogTraceListener"
initializeData="WebApiDiagnostics" />
</listeners>
</trace>
</system.diagnostics>
In your WebApiConfig.cs, you can do the following:
IAssembliesResolver assembliesResolver = config.Services.GetAssembliesResolver();
ICollection<Assembly> assemblies = assembliesResolver.GetAssemblies();
StringBuilder errorsBuilder = new StringBuilder();
foreach (Assembly assembly in assemblies)
{
Type[] exportedTypes = null;
if (assembly == null || assembly.IsDynamic)
{
// can't call GetExportedTypes on a dynamic assembly
continue;
}
try
{
exportedTypes = assembly.GetExportedTypes();
}
catch (ReflectionTypeLoadException ex)
{
exportedTypes = ex.Types;
}
catch (Exception ex)
{
errorsBuilder.AppendLine(ex.ToString());
}
}
if (errorsBuilder.Length > 0)
{
//Log errors into Event Log
Trace.TraceError(errorsBuilder.ToString());
}
BTW, some of the above code is actually from the DefaultHttpControllerTypesResolver which Web API uses to resolve the controller types.
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/Dispatcher/DefaultHttpControllerTypeResolver.cs
Edited:
One more scenario where you could hit this problem is if your controller is nested inside another class. This was a bug which was fixed later though.
Ok, so I believe I found out what was going on. I am not entirely certain, but at least my problem got fixed.
Simply by changing what was inside of the "data" field in the Ajax call and I have created a class for an object in the application to hold the whole data. It seems that for some reason the method could not have the syntax "Get(int ID)".
Instead, I did something like "Get( object)" and in the Ajax Request something like "data: obj.ID" and voila, it worked.
Also, since the framework is picky about the names of the REST methods (Get, Post, Put and Delete), I changed the name of the method to something else (like Retrieve or something).
Hopefully this will help someone in the future as well.
Best regards,
Mad
Be sure that you have the same parameter names in your methods (int id) as well as in your WebApiConfig/RouteConfig. Try it by changing
public string Get(int id)
{
return "hello";
}
to
public string Get(int? id = null)
{
return "hello";
}
I had the same problem. with me it happens due to a crush in the visual studio (2012). I had the controller file open in visual studio but it wasn't a part of my solution - I couldn't find him in the controllers directory in the solution explorer.
I just added the file to the solution by right clicking on controllers directory => add => existing item.
that fixed the problem for me.
if that doesn't work maybe try to delete the controller and add a new one with the same code . . .

FastCGI: retrieve the request headers

I’m currently working on a Web C++ application using FastCGI with Apache and mod_fcgid.
I’m trying to retrieve the headers of a request, but I didn’t find how to do so. After some researches, I thought the headers were in the attribute “envp” of “FCGX_Request”, but it contains environment variables such as:
REMOTE_ADDR: 192.168.0.50
SERVER_SOFTWARE: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/1.0.0f DAV/2 mod_fcgid/2.3.6
REDIRECT_UNIQUE_ID: TxytP38AAAEAABpcDskAAAAE
FCGI_ROLE: RESPONDER
HTTP_ACCEPT_LANGUAGE: fr
SERVER_SIGNATURE: <address>Apache/2.2.21 [etc.]
These variables offer me useful informations, but I need the real HTTP headers, and especially “Cookie”. I tried to read on the stream “in” of the “FCGX_Request” but it seems to be for the request body (POST datas). As my application is intended to be multi-threaded, I use “FCGX_Accept_r()”, like this:
while(true)
{
FCGX_Init();
FCGX_Request* fcgiRequest = new FCGX_Request;
FCGX_InitRequest(fcgiRequest, 0, 0);
if(FCGX_Accept_r(fcgiRequest) < 0)
break;
Request* request = new Request(fcgiRequest);
request->process();
}
But actually, I don’t use threads. Requests are executed one after the other.
How can I get the request headers?
Thank you.
Try the following code. It should print out the entire environment so you can find the variable you are looking for.
while(true)
{
FCGX_Init();
FCGX_Request* fcgiRequest = new FCGX_Request;
FCGX_InitRequest(fcgiRequest, 0, 0);
if(FCGX_Accept_r(fcgiRequest) < 0)
break;
char **env = fcgiRequest->envp;
while (*(++env))
puts(*env);
Request* request = new Request(fcgiRequest);
request->process();
}

Setting custom header values in an IIS ISAPI filter

I have an ISAPI filter that I am using to do URL rewriting for my CMS. I am processing SF_NOTIFY_PREPROC_HEADERS notifications, and trying to do this:
DWORD ProcessHeader(HTTP_FILTER_CONTEXT *con, HTTP_FILTER_PREPROC_HEADERS *head)
{
head->SetHeader(con, "test1", "aaa");
con->AddResponseHeaders(con, "test2:bbb\r\n", 0);
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
However, I can't seem to read these values using server variables or response headers in classic ASP or PHP. The values are missing. I'm expecting either my "test1" or "test2" header values to appear, but they are not. Am I doing something wrong here?
I finally figured it out, I was missing a ':' in the header name:
DWORD ProcessHeader(HTTP_FILTER_CONTEXT *con, HTTP_FILTER_PREPROC_HEADERS *head)
{
head->SetHeader(con, "test1:", "aaa");
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
This now creates a server variable called "HTTP_TEST1".
Seems to be correct. But both methods return a BOOL. Check them and call GetLastError() if they return FALSE.
EDIT:
I'm not quite sure but you may also try out to return SF_STATUS_REQ_FINISHED instead of SF_STATUS_REQ_NEXT_NOTIFICATION.

How do I get the system proxy using Qt?

I have the following code that I am trying to extract the systems proxy settings from:
QList<QNetworkProxy> listOfProxies = QNetworkProxyFactory::systemProxyForQuery();
foreach ( QNetworkProxy loopItem, listOfProxies ) {
qDebug() << "proxyUsed:" << loopItem.hostName();
}
I only get one item back and with a blank host name. Any ideas what I am missing?
By putting:
QNetworkProxyQuery npq(QUrl("http://www.google.com"));
QList<QNetworkProxy> listOfProxies = QNetworkProxyFactory::systemProxyForQuery(npq);
I appear get the proxy out.
QNetworkProxyQuery npq(QUrl(QLatin1String("http://www.google.com")));
Don't forget to use QLatin1String :)