/*
Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ILibDuktape_http.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_Helpers.h"
#include "ILibDuktape_EventEmitter.h"
#include "ILibDuktape_DuplexStream.h"
#include "microstack/ILibRemoteLogging.h"
#include "microstack/ILibCrypto.h"
#define DIGEST_USERNAME "\xFF_DigestUsername"
#define DIGEST_PASSWORD "\xFF_DigestPassword"
#define DIGEST_AUTHTOKEN "\xFF_DigestAuthToken"
#define HTTP_DIGEST "\xFF_HTTP_DIGEST"
#define DIGEST_CLIENT_REQUEST "\xFF_DIGEST_CLIENT_REQUEST"
#define HTTP_CLIENTREQUEST_DATAPTR "\xFF_CLIENTREQUEST_DATAPTR"
#define CLIENTREQUEST_EVENT_NAME "\xFF_CLIENTREQUEST_EVENT_NAME"
#define CLIENTREQUEST_IMSG_RSPTR "\xFF_CLIENTREQUEST_IMSG_RSPTR"
#define DIGEST2CNONCE "\xFF_DIGEST2CNONCE"
#define DIGEST2NC "\xFF_DIGEST2NONCECOUNT"
#define DIGEST2WWWAUTH "\xFF_DIGEST2WWWAUTH"
#define DIGESTCLIENTREQUEST_END_CALLED "\xFF_DIGESTCLIENTREQUEST_END_CALLED"
#define DIGESTCLIENTREQUEST_CONTINUE "\xFF_DIGESTCLIENTREQUEST_CONTINUE"
#define DIGESTCLIENTREQUEST_TmpBuffer "\xFF_DIGESTCLIENTREQUEST_TmpBuffer"
#define DIGESTCLIENTREQUEST_DIGEST "\xFF_DIGESTCLIENTREQUEST_DIGEST"
duk_ret_t ILibDuktape_httpDigest_clientRequest_response2(duk_context *ctx)
{
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "digestClientRequest");// [digestClientRequest]
int statusCode = Duktape_GetIntPropertyValue(ctx, 0, "statusCode", 0);
if (statusCode == 200)
{
duk_get_prop_string(ctx, -1, "emit"); // [digestClientRequest][emit]
duk_swap_top(ctx, -2); // [emit][this]
duk_push_string(ctx, "response"); // [emit][this][response]
duk_dup(ctx, 0); // [emit][this][response][imsg]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest: Error dispatching response event"); }
}
else
{
duk_get_prop_string(ctx, -1, "emit"); // [digestClientRequest][emit]
duk_swap_top(ctx, -2); // [emit][this]
duk_push_string(ctx, "error"); // [emit][this][error]
duk_dup(ctx, 0); // [emit][this][error][imsg]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest: Error dispatching response event"); }
}
return(0);
}
duk_ret_t ILibDuktape_httpDigest_clientRequest_onDrain(duk_context *ctx)
{
duk_push_this(ctx); // [clientRequest]
if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST))
{
duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [clientRequest][digestClientRequest]
if (duk_has_prop_string(ctx, -1, ILibDuktape_WritableStream_WSPTRS))
{
duk_get_prop_string(ctx, -1, ILibDuktape_WritableStream_WSPTRS);
ILibDuktape_WritableStream_Ready((ILibDuktape_WritableStream*)Duktape_GetBuffer(ctx, -1, NULL));
}
}
return(0);
}
duk_ret_t ILibDuktape_httpDigest_clientRequest_propagateEvent(duk_context *ctx)
{
int i, nargs = duk_get_top(ctx);
duk_push_current_function(ctx); // [func]
duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [func][digestClientRequest]
duk_get_prop_string(ctx, -1, "emit"); // [func][digestClientRequest][emit]
duk_swap_top(ctx, -2); // [func][emit][this]
duk_get_prop_string(ctx, -3, CLIENTREQUEST_EVENT_NAME); // [func][emit][this][eventName]
for (i = 0; i < nargs; ++i)
{
duk_dup(ctx, i); // [func][emit][this][eventName][params]
}
if (duk_pcall_method(ctx, 1 + nargs) != 0) { return(ILibDuktape_Error(ctx, "propagateEvent() Error")); }
return(0);
}
void ILibDuktape_httpDigest_clientRequest_IncomingMessage_PauseHandler(ILibDuktape_readableStream *sender, void *user)
{
duk_push_heapptr(sender->ctx, user); // [imsg]
duk_get_prop_string(sender->ctx, -1, "pause"); // [imsg][pause]
duk_swap_top(sender->ctx, -2); // [pause][this]
if (duk_pcall_method(sender->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(sender->ctx, "ILibDuktape_httpDigest_clientRequest_IncomingMessage_PauseHandler: Error Invoking Pause on ClientRequest: "); }
duk_pop(sender->ctx); // ...
}
void ILibDuktape_httpDigest_clientRequest_IncomingMessage_ResumeHandler(ILibDuktape_readableStream *sender, void *user)
{
duk_push_heapptr(sender->ctx, user); // [imsg]
duk_get_prop_string(sender->ctx, -1, "resume"); // [imsg][pause]
duk_swap_top(sender->ctx, -2); // [pause][this]
if (duk_pcall_method(sender->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(sender->ctx, "ILibDuktape_httpDigest_clientRequest_IncomingMessage_ResumeHandler: Error Invoking Resume on ClientRequest: "); }
duk_pop(sender->ctx); // ...
}
duk_ret_t ILibDuktape_httpDigest_clientRequest_OnData(duk_context *ctx)
{
// http.IncomingMessage.data
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, CLIENTREQUEST_IMSG_RSPTR);
ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)duk_get_pointer(ctx, -1);
duk_size_t bufferLen;
char *buffer;
buffer = Duktape_GetBuffer(ctx, 0, &bufferLen);
ILibDuktape_readableStream_WriteData(rs, buffer, (int)bufferLen);
return(0);
}
duk_ret_t ILibDuktape_httpDigest_clientRequest_OnEnd(duk_context *ctx)
{
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, CLIENTREQUEST_IMSG_RSPTR);
ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)duk_get_pointer(ctx, -1);
ILibDuktape_readableStream_WriteEnd(rs);
return(0);
}
extern void ILibWebServer_Digest_ParseAuthenticationHeader(void* table, char* value, int valueLen);
char *ILibDuktape_httpDigest_generateAuthenticationHeader(duk_context *ctx, void *digestObj, void *optionsObj)
{
int top = duk_get_top(ctx);
int NC = 0;
char *CNONCE = NULL;
char *wwwauth, *username, *password;
char *method, *path;
duk_size_t wwwauthLen;
void *ReservedMemory = ILibMemory_AllocateA(8000);
void *table = ILibInitHashTree_CaseInSensitiveEx(ReservedMemory);
int tmpLen;
char result1[33];
char result2[33];
char result3[33];
duk_push_heapptr(ctx, digestObj); // [digest]
wwwauth = (char*)Duktape_GetStringPropertyValueEx(ctx, -1, DIGEST2WWWAUTH, NULL, &wwwauthLen);
username = (char*)Duktape_GetStringPropertyValue(ctx, -1, DIGEST_USERNAME, NULL);
password = (char*)Duktape_GetStringPropertyValue(ctx, -1, DIGEST_PASSWORD, NULL);
if (!duk_has_prop_string(ctx, -1, DIGEST_AUTHTOKEN))
{
if (wwwauth == NULL || username == NULL || password == NULL) { duk_pop(ctx); return(NULL); }
}
duk_push_heapptr(ctx, optionsObj); // [digest][options]
method = (char*)Duktape_GetStringPropertyValue(ctx, -1, "method", NULL);
path = (char*)Duktape_GetStringPropertyValue(ctx, -1, "path", NULL);
duk_pop(ctx); // [digest]
ILibWebServer_Digest_ParseAuthenticationHeader(table, wwwauth, (int)wwwauthLen);
char *realm, *nonce, *opaque, *qop;
int realmLen, nonceLen, opaqueLen, qopLen;
ILibGetEntryEx(table, "realm", 5, (void**)&realm, &realmLen); if (realmLen > 0) { realm[realmLen] = 0; }
ILibGetEntryEx(table, "nonce", 5, (void**)&nonce, &nonceLen); if (nonceLen > 0) { nonce[nonceLen] = 0; }
ILibGetEntryEx(table, "opaque", 6, (void**)&opaque, &opaqueLen); if (opaqueLen > 0) { opaque[opaqueLen] = 0; }
ILibGetEntryEx(table, "qop", 3, (void**)&qop, &qopLen); if (qopLen > 0) { qop[qopLen] = 0; }
if (duk_has_prop_string(ctx, -1, DIGEST_AUTHTOKEN))
{
duk_size_t authTokenLen;
char *authToken = Duktape_GetStringPropertyValueEx(ctx, -1, DIGEST_AUTHTOKEN, NULL, &authTokenLen);
if (authTokenLen < sizeof(result1))
{
memcpy_s(result1, sizeof(result1), authToken, authTokenLen);
result1[32] = 0;
username = "admin";
tmpLen = (int)authTokenLen;
}
}
else
{
tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%s", username, realm, password);
util_md5hex(ILibScratchPad2, tmpLen, result1);
}
tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s", method, path);
util_md5hex(ILibScratchPad2, tmpLen, result2);
if (qop == NULL)
{
tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%s", result1, nonce, result2);
}
else
{
duk_get_prop_string(ctx, -1, DIGEST2CNONCE); // [digest][buffer]
CNONCE = (char*)Duktape_GetBuffer(ctx, -1, NULL);
duk_pop(ctx); // [digest]
NC = Duktape_GetIntPropertyValue(ctx, -1, DIGEST2NC, 0) + 1;
duk_push_int(ctx, NC); // [digest][NC]
duk_put_prop_string(ctx, -2, DIGEST2NC); // [digest]
tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%08x:%s:%s:%s", result1, nonce, NC, CNONCE, qop, result2);
}
util_md5hex(ILibScratchPad2, tmpLen, result3);
duk_pop(ctx); // ...
tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "Digest username=\"%s\",realm=\"%s\",nonce=\"%s\",uri=\"%s\"", username, realm, nonce, path);
if (opaque != NULL) { tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ",opaque=\"%s\"", opaque); }
tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ",response=\"%s\"", result3);
if (qop != NULL) { tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ",qop=\"%s\",nc=\"%08x\",cnonce=\"%s\"", qop, NC, CNONCE); }
if (realmLen > 0) { realm[realmLen] = '"'; }
if (nonceLen > 0) { nonce[nonceLen] = '"'; }
if (opaqueLen > 0) { opaque[opaqueLen] = '"'; }
if (qopLen > 0) { qop[qopLen] = '"'; }
duk_set_top(ctx, top);
return(ILibScratchPad2);
}
duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx)
{
void *digestClientPtr, *digestObj, *optionsObj;
int statusCode;
duk_push_this(ctx);
optionsObj = Duktape_GetHeapptrProperty(ctx, -1, ILibDuktape_CR2Options);
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "digestClientRequest");
digestClientPtr = duk_get_heapptr(ctx, -1);
duk_get_prop_string(ctx, -1, "digest");
digestObj = duk_get_heapptr(ctx, -1);
duk_get_prop_string(ctx, -1, DIGEST_USERNAME);
duk_get_prop_string(ctx, -2, DIGEST_PASSWORD);
statusCode = Duktape_GetIntPropertyValue(ctx, 0, "statusCode", -1);
if (statusCode == 401)
{
duk_push_heapptr(ctx, digestClientPtr); // [digestClientRequest]
int endCalledAlready = Duktape_GetBooleanProperty(ctx, -1, DIGESTCLIENTREQUEST_END_CALLED, 0);
if (endCalledAlready == 0 && duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST))
{
duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [digestClientRequest][clientRequest]
duk_get_prop_string(ctx, -1, "end"); // [digestClientRequest][clientRequest][end]
duk_dup(ctx, -2); // [digestClientRequest][clientRequest][end][this]
if (duk_pcall_method(ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest.onResponse(): "); }
duk_pop_2(ctx); // [digestClientRequest]
}
duk_pop(ctx); // ...
// UnAuthorized, need to retry request with Authorization Headers
char *auth, *wwwauth;
duk_dup(ctx, 0); // [IMSG]
duk_get_prop_string(ctx, -1, "headers"); // [IMSG][headers]
if ((wwwauth = Duktape_GetStringPropertyValue(ctx, -1, "WWW-Authenticate", NULL)) != NULL)
{
duk_push_heapptr(ctx, digestObj); // [IMSG][headers][digest]
duk_push_string(ctx, wwwauth); // [IMSG][headers][digest][www]
duk_put_prop_string(ctx, -2, DIGEST2WWWAUTH); // [IMSG][headers][digest]
duk_pop(ctx); // [IMSG][headers]
}
duk_pop_2(ctx); // ...
duk_push_this(ctx); // [clientRequest]
auth = ILibDuktape_httpDigest_generateAuthenticationHeader(ctx, digestObj, optionsObj);
duk_get_prop_string(ctx, -1, ILibDuktape_CR2HTTP); // [clientReqeust][http]
duk_get_prop_string(ctx, -1, "request"); // [clientRequest][http][request]
duk_swap_top(ctx, -2); // [clientRequest][request][this]
duk_get_prop_string(ctx, -3, ILibDuktape_CR2Options); // [clientRequest][request][this][options]
if(!duk_has_prop_string(ctx, -1, "headers"))
{
duk_push_object(ctx); // [clientReqeust][request][this][options][headers]
}
else
{
duk_get_prop_string(ctx, -1, "headers"); // [clientReqeust][request][this][options][headers]
}
duk_push_string(ctx, auth); // [clientReqeust][request][this][options][headers][Auth]
duk_put_prop_string(ctx, -2, "Authorization"); // [clientReqeust][request][this][options][headers]
duk_put_prop_string(ctx, -2, "headers"); // [clientReqeust][request][this][options]
duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_response2, DUK_VARARGS); // [clientReqeust][request][this][options][callback]
duk_push_heapptr(ctx, digestClientPtr); // [clientReqeust][request][this][options][callback][digestClientRequest]
duk_put_prop_string(ctx, -2, "digestClientRequest"); // [clientReqeust][request][this][options][callback]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "digest_onResponse: Error Invoking http.get"); }
duk_push_heapptr(ctx, digestClientPtr); // [clientRequest][digestClientRequest]
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "upgrade", -1, "upgrade");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "error", -1, "error");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "continue", -1, "continue");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "timeout", -1, "timeout");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "drain", -1, "drain");
duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [clientRequest]
if (endCalledAlready != 0)
{
duk_push_heapptr(ctx, digestClientPtr);
if (duk_has_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer))
{
duk_get_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer); // [clientReqeust][digestClientRequest][buffer]
duk_swap_top(ctx, -2); // [clientRequesat][buffer][digestClientRequest]
duk_pop(ctx); // [clientRequest][buffer]
duk_dup(ctx, -2); // [clientRequest][buffer][clientRequest]
duk_get_prop_string(ctx, -1, "write"); // [clientRequest][buffer][clientRequest][write]
duk_swap_top(ctx, -2); // [clientRequest][buffer][write][this]
duk_dup(ctx, -3); // [clientRequest][buffer][write][this][buffer]
duk_remove(ctx, -4); // [clientRequest][write][this][buffer]
if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "httpDigest.clientRequest.onResponse(): Error calling clientRequest.write(): "); }
duk_pop(ctx); // [clientRequest]
}
else
{
duk_pop(ctx); // [clientRequest]
}
duk_dup(ctx, -1); // [clientReqeust][clientReqeust]
duk_get_prop_string(ctx, -1, "end"); // [clientReqeust][clientReqeust][end]
duk_swap_top(ctx, -2); // [clientReqeust][end][this]
if (duk_pcall_method(ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "httpDigest.onResponse(): Error invoking ClientRequest.end(): "); }
duk_pop(ctx); // [clientRequest]
}
duk_push_heapptr(ctx, digestClientPtr); // [clientRequest][digestClientRequest]
duk_swap_top(ctx, -2); // [digestClientRequest][clientRequest]
duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [digestClientRequest]
}
else
{
duk_push_heapptr(ctx, digestClientPtr); // [digestClientRequest]
duk_del_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST);
duk_push_this(ctx);
duk_del_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST);
duk_pop(ctx);
duk_get_prop_string(ctx, -1, "emit"); // [digestClientRequest][emit]
duk_swap_top(ctx, -2); // [emit][this]
duk_push_string(ctx, "response"); // [emit][this][response]
duk_dup(ctx, 0); // [emit][this][response][IMSG]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "digestClientRequest.onResponse(): "); }
duk_pop(ctx); // ...
}
return(0);
}
duk_ret_t ILibDuktape_httpDigest_clientRequest_setter(duk_context *ctx)
{
duk_dup(ctx, 0); // [clientRequest]
duk_get_prop_string(ctx, -1, "once"); // [clientRequest][once]
duk_swap_top(ctx, -2); // [once][this]
duk_push_string(ctx, "response"); // [once][this][response]
duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_response, DUK_VARARGS); // [once][this][response][method]
duk_push_this(ctx); // [once][this][response][method][digest]
duk_put_prop_string(ctx, -2, "digest"); // [once][this][response][method]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest: Error setting clientRequest"); }
duk_pop(ctx); // ..
return(0);
}
duk_ret_t ILibDuktape_httpDigest_http_setter(duk_context *ctx)
{
duk_push_this(ctx); // [digest]
duk_dup(ctx, 0); // [digest][http]
duk_put_prop_string(ctx, -2, HTTP_DIGEST); // [digest]
return(0);
}
duk_ret_t ILibDuktape_httpDigest_digestRequest_end(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
int i;
duk_push_this(ctx); // [digestClientRequest]
if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST))
{
duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [digestClientRequest][clientRequest]
duk_get_prop_string(ctx, -1, "end"); // [digestClientRequest][clientRequest][end]
duk_swap_top(ctx, -2); // [digestClientRequest][end][this]
for (i = 0; i < nargs; ++i)
{
duk_dup(ctx, i); // [digestClientRequest][end][this][params...]
}
if (duk_pcall_method(ctx, nargs) != 0) { return(ILibDuktape_Error(ctx, "digestRequest().end() error")); }
duk_push_this(ctx);
duk_del_prop_string(ctx, -1, "DIGEST_CLIENT_REQUEST");
}
return(0);
}
ILibTransport_DoneState ILibDuktape_httpDigest_http_request_WriteHandler(struct ILibDuktape_WritableStream *stream, char *buffer, int bufferLen, void *user)
{
ILibTransport_DoneState retVal = ILibTransport_DoneState_ERROR;
duk_context *ctx = stream->ctx;
duk_push_heapptr(ctx, stream->obj); // [digestClientRequest]
if (Duktape_GetBooleanProperty(ctx, -1, DIGESTCLIENTREQUEST_CONTINUE, 0) == 0)
{
duk_size_t bufLen;
char *tmpBuffer;
if (duk_has_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer))
{
duk_get_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer); // [digestClientRequest][oldBuffer]
bufLen = duk_get_length(ctx, -1);
duk_resize_buffer(ctx, -1, bufLen + bufferLen);
tmpBuffer = (char*)Duktape_GetBuffer(ctx, -1, &bufLen);
memcpy_s(tmpBuffer + bufLen - (size_t)bufferLen, (size_t)bufferLen, buffer, (size_t)bufferLen);
duk_pop(ctx); // [digestClientRequest]
}
else
{
duk_push_dynamic_buffer(ctx, (duk_size_t)bufferLen); // [digestClientRequest][buffer]
tmpBuffer = (char*)Duktape_GetBuffer(ctx, -1, &bufLen);
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_TmpBuffer); // [digestClientRequest]
memcpy_s(tmpBuffer, bufLen, buffer, (size_t)bufferLen);
}
if (stream->endBytes > 0)
{
duk_push_true(ctx);
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_END_CALLED);
}
}
if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST))
{
duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [digestClientRequest][clientRequest]
duk_get_prop_string(ctx, -1, "write"); // [digestClientRequest][clientRequest][write]
duk_swap_top(ctx, -2); // [digestClientRequest][write][this]
if (stream->Reserved == 0)
{
duk_push_external_buffer(ctx);
duk_config_buffer(ctx, -1, buffer, (duk_size_t)bufferLen);
}
else
{
duk_push_lstring(ctx, buffer, (duk_size_t)bufferLen);
}
if (duk_pcall_method(ctx, 1) != 0)
{
ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest.clientRequest.write(): ");
retVal = ILibTransport_DoneState_ERROR;
}
else
{
retVal = duk_get_boolean(ctx, -1) ? ILibTransport_DoneState_COMPLETE : ILibTransport_DoneState_INCOMPLETE;
}
duk_pop(ctx); // [digestClientRequest]
}
duk_pop(ctx); // ...
return(retVal);
}
void ILibDuktape_httpDigest_http_request_DoneHandler(struct ILibDuktape_WritableStream *stream, void *user)
{
duk_context *ctx = stream->ctx;
duk_push_heapptr(ctx, stream->obj); // [digestClientRequest]
duk_push_true(ctx);
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_END_CALLED);
if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST))
{
duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [digestClientRequest][clientRequest]
duk_get_prop_string(ctx, -1, "end"); // [digestClientRequest][clientRequest][end]
duk_swap_top(ctx, -2); // [digestClientRequest][end][this]
if (duk_pcall_method(ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest.clientRequest.end(): "); }
duk_pop(ctx); // [digestClientRequest]
duk_del_prop_string(ctx, -1, "DIGEST_CLIENT_REQUEST");
}
duk_pop(ctx); // ...
}
duk_ret_t ILibDuktape_httpDigest_http_request_continueOccured(duk_context *ctx)
{
duk_push_this(ctx); // [digestClientRequest]
duk_push_true(ctx);
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_CONTINUE);
return(0);
}
duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
void *clientRequest = NULL;
ILibDuktape_EventEmitter *emitter;
char *auth = NULL;
int needCallEnd = 0;
duk_push_this(ctx); // [digest]
duk_get_prop_string(ctx, -1, HTTP_DIGEST); // [digest][http]
duk_get_prop_string(ctx, -1, "request"); // [digest][http][request]
duk_swap_top(ctx, -2); // [digest][request][this]
if (duk_is_string(ctx, 0))
{
duk_get_prop_string(ctx, -1, "parseUri"); // [digest][request][this][parseUri]
duk_dup(ctx, -2); // [digest][request][this][parseUri][this]
duk_dup(ctx, 0); // [digest][request][this][parseUri][this][uri]
duk_call_method(ctx, 1); // [digest][request][this][options]
needCallEnd = 1;
}
else
{
duk_dup(ctx, 0); // [digest][request][this][options]
}
// Before we make the request, let's check to see if we can put in Authorization header right now
if ((auth = ILibDuktape_httpDigest_generateAuthenticationHeader(ctx, duk_get_heapptr(ctx, -4), duk_get_heapptr(ctx, -1))) != NULL)
{
if (!duk_has_prop_string(ctx, -1, "headers"))
{
duk_push_object(ctx); // [digest][request][this][options][headers]
duk_dup(ctx, -1); // [digest][request][this][options][headers][dup]
duk_put_prop_string(ctx, -3, "headers"); // [digest][request][this][options][headers]
}
else
{
duk_get_prop_string(ctx, -1, "headers"); // [digest][request][this][options][headers]
}
duk_push_string(ctx, auth); // [digest][request][this][options][headers][auth]
duk_put_prop_string(ctx, -2, "Authorization"); // [digest][request][this][options][headers]
duk_pop(ctx); // [digest][request][this][options]
}
duk_call_method(ctx, 1); // [digest][clientRequest]
clientRequest = duk_get_heapptr(ctx, -1);
duk_get_prop_string(ctx, -1, "once"); // [clientRequest][once]
duk_swap_top(ctx, -2); // [once][this]
duk_push_string(ctx, "response"); // [once][this][response]
duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_response, DUK_VARARGS); // [once][this][response][method]
duk_push_object(ctx); // [once][this][response][method][digest-clientRequest]
ILibDuktape_WriteID(ctx, "httpDigest.clientRequest");
if (needCallEnd)
{
duk_push_true(ctx);
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_END_CALLED);
}
duk_push_this(ctx); // [once][this][response][method][digest-clientRequest][digest]
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_DIGEST); // [once][this][response][method][digest-clientRequest]
duk_push_heapptr(ctx, clientRequest); // [once][this][response][method][digest-clientRequest][clientRequest]
duk_dup(ctx, -2); // [once][this][response][method][digest-clientRequest][clientRequest][digest-clientRequest]
duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [once][this][response][method][digest-clientRequest][clientRequest]
duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [once][this][response][method][digest-clientRequest]
emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "response");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "error");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "upgrade");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "continue");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "timeout");
ILibDuktape_EventEmitter_AddOnceEx(emitter, "continue", ILibDuktape_httpDigest_http_request_continueOccured, 0);
ILibDuktape_WritableStream_Init(ctx, ILibDuktape_httpDigest_http_request_WriteHandler, ILibDuktape_httpDigest_http_request_DoneHandler, NULL);
if (nargs > 1 && duk_is_function(ctx, 1))
{
ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter_GetEmitter(ctx, -1), "response", duk_require_heapptr(ctx, 1));
}
duk_push_this(ctx); // [once][this][response][method][digest-clientRequest][digest]
duk_put_prop_string(ctx, -2, "digest"); // [once][this][response][method][digest-clientRequest]
duk_put_prop_string(ctx, -2, "digestClientRequest"); // [once][this][response][method]
if (duk_pcall_method(ctx, 2) != 0) { return(ILibDuktape_Error(ctx, "request error")); } // [clientRequest]
duk_push_heapptr(emitter->ctx, clientRequest);
duk_push_heapptr(emitter->ctx, emitter->object); // [clientRequest][digestClientRequest]
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "upgrade", -1, "upgrade");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "error", -1, "error");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "continue", -1, "continue");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "timeout", -1, "timeout");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "drain", -1, "drain");
if (needCallEnd)
{
duk_get_prop_string(ctx, -2, "end"); // [clientRequest][digestClientRequest][end]
duk_dup(ctx, -3); // [clientRequest][digestClientRequest][end][this]
duk_call_method(ctx, 0); duk_pop(ctx); // [clientRequest][digestClientRequest]
}
return(1);
}
duk_ret_t ILibduktape_httpDigest_create(duk_context *ctx)
{
duk_size_t usernameLen, passwordLen, authTokenLen;
ILibDuktape_EventEmitter *emitter;
char *username = NULL, *password = NULL, *authToken = NULL;
if (duk_get_top(ctx) == 1 && duk_is_object(ctx, 0))
{
if ((authToken = Duktape_GetStringPropertyValueEx(ctx, 0, "authToken", NULL, &authTokenLen)) == NULL) { return(ILibDuktape_Error(ctx, "authToken Required")); }
}
else
{
username = (char*)duk_require_lstring(ctx, 0, &usernameLen), password = (char*)duk_require_lstring(ctx, 1, &passwordLen);
}
duk_push_object(ctx); // [obj]
ILibDuktape_WriteID(ctx, "httpDigest");
ILibDuktape_CreateEventWithSetterEx(ctx, "clientRequest", ILibDuktape_httpDigest_clientRequest_setter);
ILibDuktape_CreateEventWithSetterEx(ctx, "http", ILibDuktape_httpDigest_http_setter);
emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "response");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "error");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "upgrade");
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "isGet", 1, "get", ILibDuktape_httpDigest_http_request, DUK_VARARGS);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "isGet", 0, "request", ILibDuktape_httpDigest_http_request, DUK_VARARGS);
if (authToken == NULL)
{
duk_push_string(ctx, username);
duk_put_prop_string(ctx, -2, DIGEST_USERNAME);
duk_push_string(ctx, password);
duk_put_prop_string(ctx, -2, DIGEST_PASSWORD);
}
else
{
duk_push_lstring(ctx, authToken, authTokenLen);
duk_put_prop_string(ctx, -2, DIGEST_AUTHTOKEN);
}
duk_push_fixed_buffer(ctx, 16);
util_randomtext(16, (char*)Duktape_GetBuffer(ctx, -1, NULL));
((char*)Duktape_GetBuffer(ctx, -1, NULL))[15] = 0;
duk_put_prop_string(ctx, -2, DIGEST2CNONCE);
duk_push_int(ctx, 0);
duk_put_prop_string(ctx, -2, DIGEST2NC);
return(1);
}
void ILibDuktape_httpDigest_PUSH(duk_context *ctx, void *chain)
{
duk_push_object(ctx);
ILibDuktape_CreateInstanceMethod(ctx, "create", ILibduktape_httpDigest_create, DUK_VARARGS);
}
duk_ret_t ILibDuktape_httpHeaders(duk_context *ctx)
{
ILibHTTPPacket *packet = NULL;
packetheader_field_node *node;
int headersOnly = duk_get_top(ctx) > 1 ? (duk_require_boolean(ctx, 1) ? 1 : 0) : 0;
duk_size_t bufferLen;
char *buffer = (char*)Duktape_GetBuffer(ctx, 0, &bufferLen);
packet = ILibParsePacketHeader(buffer, 0, (int)bufferLen);
if (packet == NULL) { return(ILibDuktape_Error(ctx, "http-headers(): Error parsing data")); }
if (headersOnly == 0)
{
duk_push_object(ctx);
if (packet->Directive != NULL)
{
duk_push_lstring(ctx, packet->Directive, packet->DirectiveLength);
duk_put_prop_string(ctx, -2, "method");
duk_push_lstring(ctx, packet->DirectiveObj, packet->DirectiveObjLength);
duk_put_prop_string(ctx, -2, "url");
}
else
{
duk_push_int(ctx, packet->StatusCode);
duk_put_prop_string(ctx, -2, "statusCode");
duk_push_lstring(ctx, packet->StatusData, packet->StatusDataLength);
duk_put_prop_string(ctx, -2, "statusMessage");
}
if (packet->VersionLength == 3)
{
duk_push_object(ctx);
duk_push_lstring(ctx, packet->Version, 1);
duk_put_prop_string(ctx, -2, "major");
duk_push_lstring(ctx, packet->Version + 2, 1);
duk_put_prop_string(ctx, -2, "minor");
duk_put_prop_string(ctx, -2, "version");
}
}
duk_push_object(ctx); // headers
node = packet->FirstField;
while (node != NULL)
{
duk_push_lstring(ctx, node->Field, node->FieldLength); // [str]
duk_get_prop_string(ctx, -1, "toLowerCase"); // [str][toLower]
duk_swap_top(ctx, -2); // [toLower][this]
duk_call_method(ctx, 0); // [result]
duk_push_lstring(ctx, node->FieldData, node->FieldDataLength);
duk_put_prop(ctx, -3);
node = node->NextField;
}
if (headersOnly == 0)
{
duk_put_prop_string(ctx, -2, "headers");
}
ILibDestructPacket(packet);
return(1);
}
void ILibDuktape_httpHeaders_PUSH(duk_context *ctx, void *chain)
{
duk_push_c_function(ctx, ILibDuktape_httpHeaders, DUK_VARARGS);
}
void ILibDuktape_http_init(duk_context * ctx, void * chain)
{
ILibDuktape_ModSearch_AddHandler(ctx, "http-digest", ILibDuktape_httpDigest_PUSH);
ILibDuktape_ModSearch_AddHandler(ctx, "http-headers", ILibDuktape_httpHeaders_PUSH);
}
#ifdef __DOXY__
/*!
\brief Http exposed using Node APIs. Note: To use, must require('http') or require('https')
*/
class Http
{
public:
/*!
\brief Parses a uri string
\param str \ The uri to parse
\return Uri object of the parsed string
*/
static Uri parseUri(str);
/*!
\brief Returns a new instance of Server
*
static Server createServer([options][, callback]);
\param options