nodejs & formidable header error - node.js

Following along with: The Node Beginner Book
I'm unable to debug this issue or find a solution online. A newbie to Node.js, hoping someone can offer a solution
ERROR: Updated with console log info Saturday, February 11, 2012 7:27:17 AM
Request for/ received!
About to route a request for /
Request handler 'start' was called.
Request for/favicon.ico received!
About to route a request for /favicon.ico
No request handler found for /favicon.ico
Request for/favicon.ico received!
About to route a request for /favicon.ico
No request handler found for /favicon.ico
Request for/upload received!
About to route a request for /upload
Request handler 'upload' was called.
about to parse
{ output: [],
outputEncodings: [],
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
_hasBody: true,
_trailer: '',
finished: false,
socket:
{ _handle:
{ writeQueueSize: 0,
socket: [Circular],
onread: [Function: onread] },
_pendingWriteReqs: 0,
_flags: 0,
_connectQueueSize: 0,
destroyed: false,
bytesRead: 66509,
bytesWritten: 638,
allowHalfOpen: true,
writable: true,
readable: true,
server:
{ connections: 1,
allowHalfOpen: true,
_handle: [Object],
_events: [Object],
httpAllowHalfOpen: false },
ondrain: [Function],
_idleTimeout: 120000,
_idleNext:
{ _idleNext: [Circular],
_idlePrev: [Circular],
ontimeout: [Function] },
_idlePrev:
{ _idleNext: [Circular],
_idlePrev: [Circular],
ontimeout: [Function] },
_idleStart: Sat, 11 Feb 2012 15:25:28 GMT,
_events: { timeout: [Function], error: [Function], close: [Object] },
ondata: [Function],
onend: [Function],
_httpMessage: [Circular] },
connection:
{ _handle:
{ writeQueueSize: 0,
socket: [Circular],
onread: [Function: onread] },
_pendingWriteReqs: 0,
_flags: 0,
_connectQueueSize: 0,
destroyed: false,
bytesRead: 66509,
bytesWritten: 638,
allowHalfOpen: true,
writable: true,
readable: true,
server:
{ connections: 1,
allowHalfOpen: true,
_handle: [Object],
_events: [Object],
httpAllowHalfOpen: false },
ondrain: [Function],
_idleTimeout: 120000,
_idleNext:
{ _idleNext: [Circular],
_idlePrev: [Circular],
ontimeout: [Function] },
_idlePrev:
{ _idleNext: [Circular],
_idlePrev: [Circular],
ontimeout: [Function] },
_idleStart: Sat, 11 Feb 2012 15:25:28 GMT,
_events: { timeout: [Function], error: [Function], close: [Object] },
ondata: [Function],
onend: [Function],
_httpMessage: [Circular] },
_events: { finish: [Function] } }
/usr/local/lib/node_modules/formidable/lib/incoming_form.js:247
undefined
if (this.headers['content-length']) {
^
TypeError: Cannot read property 'content-length' of undefined
at IncomingForm._parseContentLength (/usr/local/lib/node_modules/formidable/lib/incoming_form.js:247:19)
at IncomingForm.writeHeaders (/usr/local/lib/node_modules/formidable/lib/incoming_form.js:126:8)
at IncomingForm.parse (/usr/local/lib/node_modules/formidable/lib/incoming_form.js:80:8)
at Object.upload [as /upload] (/Applications/MAMP/htdocs3/js/nodejs/webapp/requestHandlers.js:34:8)
at route (/Applications/MAMP/htdocs3/js/nodejs/webapp/router.js:4:20)
at Server.onRequest (/Applications/MAMP/htdocs3/js/nodejs/webapp/server.js:20:3)
at Server.emit (events.js:70:17)
at HTTPParser.onIncoming (http.js:1511:12)
at HTTPParser.onHeadersComplete (http.js:102:31)
at Socket.ondata (http.js:1407:22)
End Error
requestHandlers.js
var querystring = require("querystring"),
fs = require("fs"),
formidable = require("formidable");
function start(response) {
console.log("Request handler 'start' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" enctype="multipart/form-data" '+
'method="post">'+
'<input type="file" name="upload" multiple="multiple">'+
'<input type="submit" value="Upload file" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, request) {
console.log("Request handler 'upload' was called.");
var form = new formidable.IncomingForm();
console.log("about to parse");
form.parse(request, function(error, fields, files) {
console.log("parsing done");
/*
* Some systems [Windows] raise an error when you attempt to rename new file into one that already exists.
* This call deletes the previous .PNG image prior to renaming the new one in its place.
*/
fs.unlinkSync(__dirname +"/tmp/test.jpg");
fs.renameSync(files.upload.path, "/tmp/test.jpg");
response.writeHead(200, {"Content-Type": "text/html"});
response.write("received image:<br/>");
response.write("<img src='/show' />");
response.end();
});
}
function show(response) {
console.log("Request handler 'show' was called.");
fs.readFile(__dirname + "/tmp/test.jpg", "binary", function(error, file) {
if(error) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(error + "\n");
response.end();
} else {
response.writeHead(200, {"Content-Type": "image/jpg"});
response.write(file, "binary");
response.end();
}
});
}
exports.start = start;
exports.upload = upload;
exports.show = show;
index.js
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
handle["/show"] = requestHandlers.show;
server.start(router.route, handle);
router.js
function route(handle, pathname, response, request) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname](response, request);
} else {
console.log("No request handler found for " + pathname);
response.writeHead(404, {"Content-Type": "text/html"});
response.write("404 Not found");
response.end();
}
}
exports.route = route;
server.js
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(handle, pathname, response, request);
}
// http.createServer(onRequest).listen(8888);
// console.log("Server has started.");
http.createServer(onRequest).listen(1337, "127.0.0.1");
console.log('Server Has Started!');
}
exports.start = start;

No need to use old versions of Node and Formidable. I was able to get the example to work with Node v0.10.20 and Formidable v1.0.14. It would appear that the files.upload property is no longer used.
Simply change this following line from the book:
fs.rename(files.upload.path, "/tmp/test.png", function(error) { ... });
to
fs.rename(files.file.path, "/tmp/test.png", function(error) { ... });
...and then the upload works perfectly!
Another optional tweak to the example (especially for Windows developers)
Rather than using the error status from fs.rename() to determine if the file already exists, I had great luck using fs.exists() to do check for the existing file that felt like less of a hack. I also saved the test.png file to the local directory, since /tmp is a pretty unnatural Windows path...
var img = "./test.png";
...
fs.exists(img, function(exists){
if(exists){ fs.unlink(img); }
fs.rename(files.file.path, img);
...

For what it is worth the above code worked for me.
The problem seems to occur within formidable. Checking the package.json in node_modules I am using version 1.0.8 on node -v = v0.4.12.
It appears the browser or request you are making does not include a content-length header in the request. I was using Chrome, but if you were using CURL or perhaps making the request asynchronously or as a stream you might not have a content-length header in the request causing this issue. This is somewhat discussed here:
https://github.com/felixge/node-formidable/issues/93
In my opinion, formidable should check for the existence of the parameter properly (typeof(this.headers['content-length']) != undefined). It would help others if you identify your browser and type of file you were trying to upload, then you could file a bug over at https://github.com/felixge/node-formidable/
Note: you might also update the title of this question to nodejs not nodjs. Good luck with node!

If you use the same versions of Formidable and Node.js as used in the tutorial, the code works as advertised.
The version of Formidable used in the tutorial is 1.0.2. To obtain this version, issue:
$ sudo npm install formidable#1.0.2
The version of Node.js is 0.6.10, which can be found here: https://github.com/joyent/node/tags

Well I have the same code that you, but with a little change in function upload on RequestHandlers.js,
try changing this:
function upload(response, request) {
...
var form = new formidable.IncomingForm();
...
}
to this:
function upload(response, request){
...
var form = new formidable.IncomingForm(), files = [], fields = [];
...
}
If that doesn't work you should be able to see how is the request header forming :
function upload(response, request){
...
form.parse(request, function(error, fields,files){
console.dir(request.headers);
...
}
}
Hope you solve your problem

Related

Sendgrid on FB Cloud functions, random requests fail with timeout error

This issue has been happening for a few weeks, some of our emails are not going out, and the SendGrid SDK (#sendgrid/mail for NodeJs) errors out with timeout, we have bumped the timeout time to 20000ms, but we still have some failures.
The way our scheduler system works we save a document in a document DB that holds the metadata for the email and that holds the ID of a GCP task, the GCP task calls happen 100%, and depending on the result it marks the document in the DB as "complete" or "failed", so we notice that those tasks that should be sending an email are marked as failed, and checking our Sentry logs those always have a "timeout" error.
The intriguing part is that some of those errored tasks did actually send an email, so we need to be safe on how to retry those on failure to avoid cases where we send the same email multiple times.
A few key points:
If we don't set a "timeout" value in the Sendgrid config, it won't error out, so the task will be marked as complete even if no email goes out.
Over 95% of our email tasks go out correctly, we were not able to link it to a time of the day or type of the email payload or specific email address, everything looks random, but I am sure there is a reason for those failures
Could it be related to it running in a cloud function? The stack runs on Firebase cloud functions, we have a few debug logs to help it and all the logs show up correctly and the function finalizes the execution correctly
Example of our sender method:
async function sendMail(templateName, msg, worker = {}) {
try {
const API_KEY = functions.config().sendgrid.key;
sgMail.setApiKey(API_KEY);
// https://github.com/sendgrid/sendgrid-nodejs/tree/main/docs/use-cases
sgMail.setTimeout(20000);
const env = getEnvironment();
if (env === "development") {
msg.to = "our-test-email#gmail.com";
}
msg.templateId = functions.config().sendgrid[templateName];
const response = await sgMail.send(msg);
console.log(`DEBUG: ${msg.to} Sendgrid response:`, response);
return response;
} catch (error) {
if (error.response && error.response.body) {
console.error(error.response.body);
} else {
console.log(error);
}
Sentry.withScope(function (scope) {
!isEmpty(worker) &&
scope.setUser({
firstName: user.firstName,
lastName: user.lastName,
});
Sentry.captureException(error);
});
// Throw back the error to the caller to mark the task as failed
throw new functions.https.HttpsError(
"internal",
msg.to ? `Error sending email to ${msg.to}` : "Error sending email",
error
);
}
}
One example of the error:
Error: timeout of 20000ms exceeded
File "/layers/google.nodejs.yarn/yarn_modules/node_modules/#sendgrid/client/node_modules/axios/lib/core/createError.js", line 16, col 15, in createError
var error = new Error(message);
File "/layers/google.nodejs.yarn/yarn_modules/node_modules/#sendgrid/client/node_modules/axios/lib/adapters/http.js", line 303, col 16, in RedirectableRequest.handleRequestTimeout
reject(createError(
File "node:events", line 527, col 28, in RedirectableRequest.emit
File "node:domain", line 537, col 15, in RedirectableRequest.emit
File "/layers/google.nodejs.yarn/yarn_modules/node_modules/follow-redirects/index.js", line 164, col 12, in Timeout.<anonymous>
self.emit("timeout");
File "node:internal/timers", line 559, col 17, in listOnTimeout
File "node:internal/timers", line 502, col 7, in processTimers
Extra response metadata:
scheduler/sender -> sendCompanyEmail() Company: FgTgemCNhhAscqTTMTWa Message: EMAIL HttpsError: Error sending email to ops-dev#trabapro.com
at sendMail (/workspace/lib/src/helpers/index.js:67:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async /workspace/lib/src/scheduler/sender.js:306:17
at async Promise.all (index 0)
at async sendCompanyEmail (/workspace/lib/src/scheduler/sender.js:303:13) {
code: 'internal',
details: Error: timeout of 20000ms exceeded
at createError (/layers/google.nodejs.yarn/yarn_modules/node_modules/#sendgrid/client/node_modules/axios/lib/core/createError.js:16:15)
at RedirectableRequest.handleRequestTimeout (/layers/google.nodejs.yarn/yarn_modules/node_modules/#sendgrid/client/node_modules/axios/lib/adapters/http.js:303:16)
at RedirectableRequest.emit (node:events:527:28)
at RedirectableRequest.emit (node:domain:537:15)
at Timeout.<anonymous> (/layers/google.nodejs.yarn/yarn_modules/node_modules/follow-redirects/index.js:164:12)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7) {
config: {
url: '/v3/mail/send',
method: 'post',
data: ...
...
baseURL: 'https://api.sendgrid.com/',
transformRequest: [Array],
transformResponse: [Array],
timeout: 20000,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: Infinity,
maxBodyLength: Infinity,
validateStatus: [Function: validateStatus],
transitional: [Object]
},
code: 'ECONNABORTED',
request: Writable {
_writableState: [WritableState],
_events: [Object: null prototype],
_eventsCount: 3,
_maxListeners: undefined,
_options: [Object],
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 1557,
_requestBodyBuffers: [Array],
_onNativeResponse: [Function (anonymous)],
_currentRequest: [ClientRequest],
_currentUrl: 'https://api.sendgrid.com/v3/mail/send',
_timeout: null,
[Symbol(kCapture)]: false
},
response: undefined,
isAxiosError: true,
toJSON: [Function: toJSON]
},
httpErrorCode: { canonicalName: 'INTERNAL', status: 500 }
```

Tunnel-SSH doesn't connect to server successful in node application

I'm trying to connect to a cloud server that runs my MongoDB from my local machine. I'm using tunnel-ssh within the Node.js application I'm creating, however, I seem to have multiple problems and I don't fully understand what's going on.
Problems
I'm not 100% sure I'm successfully connecting to the server. There's no error, however, when I console.log(server) it says _connections: 0,. see full log below.
If I am connecting and then I try to run the getDataFromMongoDB function it returns the error, EADDRINUSE: address already in use 127.0.0.1:27000.
I've been trying to wrap my head around this all day and I'm not getting anywhere. Please help.
Error 1 - Is server connecting
Server {
_events:
[Object: null prototype] { connection: [Function], close: [Function] },
_eventsCount: 2,
_maxListeners: undefined,
_connections: 0,
_handle:
TCP {
reading: false,
onread: null,
onconnection: [Function: onconnection],
[Symbol(owner)]: [Circular] },
_usingWorkers: false,
_workers: [],
_unref: false,
allowHalfOpen: false,
pauseOnConnect: false,
_connectionKey: '4:127.0.0.1:27017',
[Symbol(asyncId)]: 7 }
Code
var config = {
username: "root",
Password: "password on the server",
host: "server IP address",
port: 22,
dstHost: "127.0.0.1",
dstPort: 27017,
localHost: "127.0.0.1",
localPort: 27000
};
var tnl = tunnel(config, function(error, tnl) {
if (error) {
console.log(error);
}
// yourClient.connect();
// yourClient.disconnect();
console.log(tnl);
getDataFromMongoDB();
});
async function getDataFromMongoDB(page) {
const MongoClient = require("mongodb").MongoClient;
const uri = "mongodb://USRNAME:PASSWORD_FOR_MONGDB_DATABASE#localhost:27017";
const client2 = new MongoClient(uri, { useNewUrlParser: true });
const client = await connectToMongodb(client2);
const collection = client.db("my_database_name").collection("jobs");
const jobs = await collection.find().toArray();
console.log("jobs", jobs);
}
function connectToMongodb(client) {
return new Promise((resolve, reject) => {
client.connect(function(err) {
console.log("connected", err);
return resolve(client);
});
});
}

How to parse a json file with nodejs

I got a little problem with the nodejs fetch module and more particularly with the JSON parse. When I want to parse the stock variable, he tells me that the size is equal to 0 ? But my file is not empty and the path is good.
The code is really simple but I don't know why this error append and I spend too much time on this.
Someone know why I get this error and how I can resolve it ?
here the code of my js file :
const fetch = require('node-fetch');
const keyword='test';
const url='http://localhost:8888/test.json';
fetch(url).then((stock) => {
console.log(stock);
const jsonFile = JSON.parse(stock);
const newCategory = jsonFile[test];
console.log(newCategory);
}).catch((e)=>{console.log(e)});
And the error in my terminal with the first console.log() :
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]:
{ body:
PassThrough {
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: true,
_transformState: [Object] },
disturbed: false,
error: null },
[Symbol(Response internals)]:
{ url: 'http://localhost:8888/test.json',
status: 200,
statusText: 'OK',
headers: Headers { [Symbol(map)]: [Object] },
counter: 0 } }
SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse (<anonymous>)
at fetch.then (/Users/me/Desktop/test_json/index.js:11:30)
at process._tickCallback (internal/process/next_tick.js:68:7)
The fetch api returns a Body object
you can call Body.json()
Using async/await:
const body = await fetch(url);
const json = await body.json();
console.log(json);
Using promises:
fetch(url).then((stock) => {
return stock.json()
}).then(json => {
console.log(json);
});
JSON.parse:
fetch(url).then((stock) => {
return stock.text()
}).then(text => {
console.log(JSON.parse(text));
});
You need to pass the body in json parse like bellow,
JSON.parse(stock.text())
Or you can directly use json data without parsing just using stock.json() function

node-soap - Proper method of calling function

I know absolutely nothing about SOAP lol, But a vital part of my software requires I use it for a particular webservice. The documentation for the webservice was written for .net so it makes it even harder for me to understand what I need to do here. On top of all that they require authentication.
For the connecting I do not need to authorize so I am able to retreive the describe function result. They are as follows:
I20151214-09:20:20.381(-8)? Getting inside soap client creation method
I20151214-09:20:20.722(-8)? Exception while invoking method 'createSoapClient' TypeError: Cannot call method 'describe' of undefined
I20151214-09:20:20.723(-8)? at Object.Soap.createClient (packages/zardak_soap/packages/zardak_soap.js:37:1)
I20151214-09:20:20.724(-8)? at [object Object].Meteor.methods.createSoapClient (controllers/server/testFiles.js:21:1)
I20151214-09:20:20.724(-8)? at maybeAuditArgumentChecks (livedata_server.js:1698:12)
I20151214-09:20:20.725(-8)? at livedata_server.js:708:19
I20151214-09:20:20.725(-8)? at [object Object]._.extend.withValue (packages/meteor/packages/meteor.js:1013:1)
I20151214-09:20:20.726(-8)? at livedata_server.js:706:40
I20151214-09:20:20.726(-8)? at [object Object]._.extend.withValue (packages/meteor/packages/meteor.js:1013:1)
I20151214-09:20:20.726(-8)? at livedata_server.js:704:46
I20151214-09:20:20.727(-8)? at tryCallTwo (C:\Users\Media Center\AppData\Local\.meteor\packages\promise\0.5.1\npm\node_modules\meteor-promise\node_modules\promise\lib\core.js:45:5)
I20151214-09:20:20.727(-8)? at doResolve (C:\Users\Media Center\AppData\Local\.meteor\packages\promise\0.5.1\npm\node_modules\meteor-promise\node_modules\promise\lib\core.js:171:13)
I20151214-09:20:21.996(-8)? Getting inside the return of the create client
I20151214-09:20:22.007(-8)? { PRIMEStandardV1_1:
I20151214-09:20:22.008(-8)? { PRIMEStandardV1_1Soap:
I20151214-09:20:22.009(-8)? { RunTrip: [Object],
I20151214-09:20:22.009(-8)? ReverseGeocode: [Object],
I20151214-09:20:22.010(-8)? FindLocationsInRadius: [Object],
I20151214-09:20:22.010(-8)? FindLocationsOnRoute: [Object],
I20151214-09:20:22.010(-8)? FindLocationsInState: [Object],
I20151214-09:20:22.011(-8)? GetAverageDieselPriceInState: [Object],
I20151214-09:20:22.012(-8)? TestRadiusGeofence: [Object],
I20151214-09:20:22.012(-8)? TestRouteGeofence: [Object],
I20151214-09:20:22.013(-8)? RunSimpleTrip: [Object],
I20151214-09:20:22.013(-8)? Geocode: [Object],
I20151214-09:20:22.014(-8)? GetTodaysUSDieselAverage: [Object],
I20151214-09:20:22.014(-8)? GetTodaysCanadianDieselAverage: [Object],
I20151214-09:20:22.015(-8)? GetTripDistance: [Object],
I20151214-09:20:22.016(-8)? ValidateLocation: [Object] },
I20151214-09:20:22.017(-8)? PRIMEStandardV1_1Soap12:
I20151214-09:20:22.017(-8)? { RunTrip: [Object],
I20151214-09:20:22.018(-8)? ReverseGeocode: [Object],
I20151214-09:20:22.019(-8)? FindLocationsInRadius: [Object],
I20151214-09:20:22.021(-8)? FindLocationsOnRoute: [Object],
I20151214-09:20:22.021(-8)? FindLocationsInState: [Object],
I20151214-09:20:22.022(-8)? GetAverageDieselPriceInState: [Object],
I20151214-09:20:22.022(-8)? TestRadiusGeofence: [Object],
I20151214-09:20:22.023(-8)? TestRouteGeofence: [Object],
I20151214-09:20:22.023(-8)? RunSimpleTrip: [Object],
I20151214-09:20:22.024(-8)? Geocode: [Object],
I20151214-09:20:22.025(-8)? GetTodaysUSDieselAverage: [Object],
I20151214-09:20:22.025(-8)? GetTodaysCanadianDieselAverage: [Object],
I20151214-09:20:22.026(-8)? GetTripDistance: [Object],
I20151214-09:20:22.026(-8)? ValidateLocation: [Object] } } }
caseless:
I20151216-11:53:14.658(-8)? { dict:
I20151216-11:53:14.658(-8)? { 'cache-control': 'private',
I20151216-11:53:14.659(-8)? 'content-type': 'text/xml; charset=utf- 8',
I20151216-11:53:14.659(-8)? server: 'Microsoft-IIS/7.0',
I20151216-11:53:14.660(-8)? 'x-aspnet-version': '4.0.30319',
I20151216-11:53:14.660(-8)? 'x-powered-by': 'ASP.NET',
I20151216-11:53:14.661(-8)? date: 'Wed, 16 Dec 2015 19:40:29 GMT',
I20151216-11:53:14.661(-8)? connection: 'close',
I20151216-11:53:14.662(-8)? 'content-length': '441' } },
I20151216-11:53:14.662(-8)? pipe: [Function],
I20151216-11:53:14.663(-8)? addListener: [Function: addListener],
I20151216-11:53:14.664(-8)? on: [Function: addListener],
I20151216-11:53:14.665(-8)? pause: [Function],
I20151216-11:53:14.665(-8)? resume: [Function],
I20151216-11:53:14.666(-8)? read: [Function],
I20151216-11:53:14.666(-8)? body: 'soap:ServerServer was unable to process request. ---> Object reference not set to an instance of an object.' }
I20151216-11:53:16.716(-8)? Error: [object Object]
I20151216-11:53:16.722(-8)? { Envelope: { Body: { Fault: [Object] } } }
I20151216-11:53:16.723(-8)? undefined
As you can see I am able to connect. Now the part that is trowing me off is to actually call one of these functions. Below is the code I am using to try to call the "RunSimpleTrip". However when I console log the Result it is a huge jumble of messages that end up running the buffer out on my cmd window and I can only see back a little ways none of it making sense.
var url = 'http://prime.promiles.com/Webservices/v1_1/PRIMEStandardV1_1.asmx?wsdl';
var simpleTrip = {
AvoidTollRoads: false,
BorderOpen: true,
RoutingMethod: "PRACTICAL",
TripLegs: [{LocationText: "77611"},
{LocationText: "90210"}]
}
Soap.createClient(url, function(err, client) {
console.log(client.describe());
client.setSecurity(new Soap.BasicAuthSecurity('hoperd', 'mailaaron', 'bkkyt'));
client.PRIMEStandardV1_1.PRIMEStandardV1_1Soap.RunSimpleTrip(simpleTrip, function(err, result, raw, soapHeader) {
//console.log("Result: ");
console.log(result);
console.log("Error: " + err.root);
console.log(err.root);
console.log(soapHeader);
// result is a javascript object
// raw is the raw response
// soapHeader is the response soap header as a javascript object
})
});
From the API's documentation this is how they call the same function using .net
PRIMEEnterpriseV1 PRIME = new PRIMEEnterpriseV1();
//Authorization Credentials
Credentials c = new Credentials();
c.Username = "MyUsername;
c.Password = "MyPassword";
c.CompanyCode ="MyCompanyCode";
SimpleTrip st = new SimpleTrip();
st.AvoidTollRoads = false;
st.BorderOpen = true;
st.RoutingMethod = com.promiles.PRIME.Enterprise.RouteMethod.PRACTICAL;
TripLeg[] Legs = new TripLeg[2];
//Origin
TripLeg t = new TripLeg();
t.LocationText = "77611";
Legs[0] = t;
//Destination
t = new TripLeg();
t.LocationText = "90210";
Legs[1] = t;
st.TripLegs = Legs;
//Call Function
SimpleTrip rt = PRIME.RunSimpleTrip(c, st);
I am hoping someone our there has a clue to this mystery for me or can point me in the right direction as to how to properly connect this this. Any and all help will be greatly appreciated.
So after much trial and error I was able to figure this out. The below code works to call the SimpleTrip and return a proper response from the server. My TripLegs arg still isn't 100% correct to what the SOAP is looking for but the code and the way to call it is.
var url = 'http://prime.promiles.com/Webservices/v1_1/PRIMEStandardV1_1.asmx?wsdl';
var credentials = { Username: "xxxxx",
Password: "xxxxxx",
CompanyCode: "xxxxx"
};
var simpleTrip = {
AvoidTollRoads: false,
BorderOpen: true,
RoutingMethod: "PRACTICAL",
VehicleType: "Tractor2AxleTrailer2Axle",
TripLegs: [{Location: {LocationText: "77611"}},
{Location: {LocationText: "90210"}}]
}
args = {c: credentials, BasicTrip: simpleTrip};
Soap.createClient(url, function(err, client) {
console.log(err);
console.log(simpleTrip);
client.RunSimpleTrip(args, function(err, result, raw, soapHeader) {
console.log(result);
//console.log(err.root);
console.log(err.root.Envelope);
})
});

ExpressJS res.render() error (JSON.stringify can't work on circular reference)

What's wrong here?
res.render('/somepage', {user:req.session.user})
It leads to Converting circular structure to JSON errors, (results in session element that has a circular user reference.)
exports.home = function (req, res) {
var entityFactory = new require('../lib/entity-factory.js').EntityFactory();
entityFactory.get_job_task_lists({
callback : function (err, job_task_lists) {
res.render('home.jade', {
locals:{
title: 'Logged in.',
user:req.session.user, // does not work
job_task_lists:job_task_lists || []
}
});
}
});
};
I added some logging in node_modules/express/node_modules/connect/lib/middleware/session/memory.js
MemoryStore.prototype.set = function(sid, sess, fn){
var self = this;
process.nextTick(function(){
console.log(sess); //this is giving the output listed
self.sessions[sid] = JSON.stringify(sess);
...
This is what I expect the session to look like, in terms of structure:
{ lastAccess: 1330979534026,
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 06 Mar 2012 00:32:14 GMT,
originalMaxAge: 14399999 },
user: // this is the object I added to the session
{ id: 1,
username: 'admin',
password: '8e3f8d3a98481a9073d2ab69f93ce73b',
creation_date: Mon, 05 Mar 2012 18:08:55 GMT } }
But here's what I find:
{ lastAccess: 1330979534079, // new session
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 06 Mar 2012 00:32:14 GMT,
originalMaxAge: 14399999 },
user: // but here it is again, except now it's a mashup,
// containing members it shouldn't have, like locals,
// and, well, everything but the first 4 properties
{ id: 1,
username: 'admin',
password: '8e3f8d3a98481a9073d2ab69f93ce73b',
creation_date: '2012-03-05T18:08:55.701Z',
locals:
{ title: 'Logged in.',
user: [Circular], //and now it's circular
job_task_lists: [Object] },
title: 'Logged in.',
user: [Circular],
job_task_lists: [ [Object], [Object], [Object], getById: [Function] ],
attempts: [ '/home/dan/development/aqp/views/home.jade' ],
scope: {},
parentView: undefined,
root: '/home/dan/development/aqp/views',
defaultEngine: 'jade',
settings:
{ env: 'development',
hints: true,
views: '/home/dan/development/aqp/views',
'view engine': 'jade' },
app:
{ stack: [Object],
connections: 6,
allowHalfOpen: true,
_handle: [Object],
_events: [Object],
httpAllowHalfOpen: false,
cache: [Object],
settings: [Object],
redirects: {},
isCallbacks: {},
_locals: [Object],
dynamicViewHelpers: {},
errorHandlers: [],
route: '/',
routes: [Object],
router: [Getter],
__usedRouter: true },
partial: [Function],
hint: true,
filename: '/home/dan/development/aqp/views/home.jade',
layout: false,
isPartial: true } }
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Converting circular structure to JSON
at Object.stringify (native)
at Array.0 (/home/dan/development/aqp/node_modules/express/node_modules/connect/lib/middleware/session/memory.js:77:31)
at EventEmitter._tickCallback (node.js:192:40)
See how the user object is nested?
Note that this time I did not send values in explicitly with 'locals' but it ended up in one (thats the source of the circular reference.
It looks like the session is being used to transfer objects to the view.
Here's my only middleware (it only reads from the session):
function requiresAuthentication(req, res, next){
if (req.session.user){
next();
} else {
next(new Error('Unauthorized. Please log in with a valid account.'))
}
}
and the only time I modify the req.session is in this route:
app.post('/home', function (req,res,next) {
var auth = require('./lib/authentication');
auth.authenticate_user(req.body.user, function (user) {
if (user){
req.session.user = user;
console.log('authenticated');
res.redirect(req.body.redir || '/home');
//next();
} else {
console.log('not authenticated');
res.render('logins/new.jade', {title: 'Login Failed', redir:''})
}
});
});
I don't have much else going on in my application yet, as it's still quite young. I know I'm not mangling the session anywhere myself; I checked.
I did some more testing, and it appears this is only an issue when I then try to use the local variable on a page. For instance, here is my view home.jade
div(data-role="page")
div(data-role="header")
a(href='/logout', data-icon='delete', data-ajax="false") Log out
h1= title
a(href='/account', data-icon='info', data-ajax="false") Account
!= partial('user', user)
each jtl in job_task_lists
div(id=jtl.name, class = 'draggable_item', style='border:2px solid black;')
#{jtl.name} - #{jtl.description}
a(data-icon='plus')
div(data-role="footer")
h3 footer
script(src="/javascripts/home.js")
If I comment out the user partial, it renders, else I get this Converting circular structure to JSON issue.
UPDATE
So after hooking up eclipse and the v8 debugger, I have been stepping through the code and I know where the mashup of session and user objects is occurring,
in node_modules/connect/lib/middleware/session/session.js
utils.union ends up mashing the members of the user object into the session, causing the circular reference. I'm just not sure why (admittedly probably my code)
This was a problem with session data being modified in a view.
After much digging, I found that it was a bug in the way partials are handled in 2.5.8. I submitted an issue, and subsequently a patch. (in case anyone needs this info at a future date) as npm is still serving up Express 2.5.8 AFAIK.
Thanks for your help #freakish and #Ryan

Resources