Decode Url Recursively giving error for valid URL - javascript

I have trying to decode Recursively encoded url . But for even valid URL it is giving error .
I am calling
decodeURIRecursively({},"https%3A%2F%2Fgmail.com%3Frate%3D95%25")
It should return "https://gmail.com?rate=95%" But return string.
If I modify code and change catch block to return url it works well for this scenario but for malformed URL like decodeURIRecursively({},'%E0%A4%A'). It gives same url .
const decodeURIRecursively = (req, url) => {
// Early return on missing required parameter
if (!req || !url) {
return '';
}
try {
while (decodeURIComponent(url) !== url) {
url = decodeURIComponent(url);
}
} catch (e) {
return ''; // Return empty string as it is not a safe string to decode and use in
}
return url;
};
console.log(decodeURIRecursively({},"https%3A%2F%2Fgmail.com%3Frate%3D95%25"));

The url "https://gmail.com?rate=95%" has one invalid character which is "%".
So that why you get exception when run final step decodeURLComponent.
%3A, %2F, %3F... can be decode but only "%" is impossible.
catch (e) {
return url;
}
Return url when get the error is good choice as you mentioned.
My question is why you need decode recursively?
As I see you only need run decodeURLComponent one time.

Related

Issues with identifying and encoding urls

I'm having issues with parsing/manipulating URI:
Problem Statement:
I want to encode f[users.comma] and return it.
[Case-1] I get an url from backend service, encode f[users.comma] and return it.
[Case-2] I get an url from backend service and f[users.comma] is already encoded. So don't double encode and return it.
Expected Output:
`/demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%2C+Georgia%22`
Code:
const encodedExample = `/demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%2C+Georgia%22` // the last param is encoded
const regularExample2 = `/demo/bigquery/order_items?fields=users.email&f[users.comma]="Abbeville, Georgia"` //
const specialEncode = (url) => {
for (let queryParam of urlObj) {
const [urlKey, urlValue] = queryParam
// Check to see if url contains f[users.comma]
if (urlKey.includes('f[')) {
urlObj.set(urlKey, encodeURI(urlValue))
}
}
return urlObj.toString() // doesn't seem to work
}
I feel like I am going offroad with my approach. I'd appreciate some help here.
Since the backend service returns an encoded or decode url
We can first decode the url from the backend service (this won't produce any exceptions if url is already encoded)
const encodedExample = `/demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%2C+Georgia%22` // the last param is encoded
const regularExample2 = `/demo/bigquery/order_items?fields=users.email&f[users.comma]="Abbeville, Georgia"`
const specialEncode = (url) => {
let decodedUrl = decodeURI(url);
let encodedUrl = encodeURI(decodedUrl);
// fix "f[users.comma]" because encodeURI will encode the [ and ] as well
encodedUrl = encodedUrl.replace("f%5Busers.comma%5D", "f[users.comma]")
console.log(encodedUrl);
return encodedUrl;
}
specialEncode(encodedExample); // logs and returns: /demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%252C+Georgia%22
specialEncode(regularExample2); // logs and returns: /demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%252C+Georgia%22
The code above works fine for both encoded and decoded urls

Get a specific response header (e.g., Content-Disposition) in React from an ASP.NET CORE Web Api

I am returning a file from a WebAPI controller. The Content-Disposition header value is automatically filled, and it contains also my filename.
My backend code looks like this:
[HttpGet("Download")]
public async Task<ActionResult> Download([FromQuery]CompanySearchObject req)
{
string fileName = "SomeFileName_" + DateTime.UtcNow.Date.ToShortDateString() + ".csv";
var result = await _myService.GetData(req);
Stream stream = new System.IO.MemoryStream(result);
return File(stream, "text/csv", fileName.ToString());
}
And on my frontend:
exportData(params).then(response => {
console.log(response);
console.log('Response Headers:', response.headers);
const type = response.headers['content-type'];
const blob = new Blob([response.data], { type: type, encoding: 'UTF-8' });
//const filename = response.headers['content-disposition'].split('"')[1];
//alert(filename);
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'file.xlsx';
link.click();
link.remove();
});
};
But I'm struggling to fetch this data, because when I do console.log on frontend I can not see this.. as you can see I logged response console.log('Response Headers:', response.headers); but only thing I see is:
Shouldn't this data be somewhere? I'm wondering how can I read value from Content-Disposition and get filename?
Thanks guys
Cheers
Had the same problem. My problem was CORS. If you are using it, you need to expose it like this in your configuration:
app.UseCors(builder =>
{
builder.AllowAnyOrigin();
builder.AllowAnyMethod();
builder.AllowAnyHeader();
builder.WithExposedHeaders("Content-Disposition"); // this is the important line
});
The way I do it is by looping through all the request headers until I match the specific header I'm looking for.
// Headers
private void GetSetCustomHeaders(ref string theUsername, ref string thePassword, ref string theAPIKey)
{
try
{
foreach (KeyValuePair<string, IEnumerable<string>> header in this.Request.Headers)
{
string headerType = header.Key;
string headerTypeUpperTrim = headerType.Trim().ToUpper();
IEnumerable<string> headerValue = header.Value;
string fullHeaderValue = "";
bool isFirstHeaderValue = true;
foreach (string headerValuePart in headerValue)
{
if (isFirstHeaderValue)
{
fullHeaderValue = headerValuePart;
isFirstHeaderValue = false;
}
else
{
fullHeaderValue = fullHeaderValue + Environment.NewLine + headerValuePart;
}
}
if (headerTypeUpperTrim == "USERNAME")
{
theUsername = fullHeaderValue;
}
else if (headerTypeUpperTrim == "PASSWORD")
{
thePassword = fullHeaderValue;
}
else if (headerTypeUpperTrim == "APIKEY")
{
theAPIKey = fullHeaderValue;
}
}
}
catch (Exception)
{
//MessageBox.Show("Error at 'GetSetCustomHeaders'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
In the example code above I'm looking for 'Username', 'Password' and 'APIKey'. They are passed through as ref parameters so If they're set in this method, they're set in the method calling this GetSetCustomHeaders method as well, because it references the same thing. So when I call this method initially my variables are set to string.Empty.
Hope this is helpful.
For Fetch Response Headers, it returns is an iterable, you have to loop through response.headers instead of log response.headers object.
Try code below:
response.headers.forEach(console.log);
console.log(response.headers.get('content-disposition'));
This is correct I face this issue.Try that.
It can be resolve only server side(Back end side).You must be add back end response headers like this,
Access-Control-Expose-Headers: [Content-Disposition , .....You can add multiple heders]
After that you can directly access this header using response.headers

Issue Parsing JSON Response

I'm using AJAX/JQuery to call a WCF service. I have some .NET try/catch error-handling on the service-side that checks to see if the user has timed out, and if they have then I pass back a JSON-converted message which I then parse out on the client-end using parseJSON and use it to re-direct the user back a login page.
This is all working great, but I just got a different type of error returned from the service that WASN'T in JSON format (it was XML) so the error-handling function got a javascript error on the client side when it tried to parse the reply. The error was in the jquery.min.js file, and was an 'Invalid character' error.
My question (finally), is there a better way to handle that reply if I can't always rely on it being JSON? In .NET we have a tryParse method available that would work great here, but as far as I know JQuery/Javascript has no such feature. If it can't parse the reply, it throws a JS error.
Here is where the custom JSON exception is thrown:
private HttpSessionState GetUserSession()
{
HttpSessionState session = HttpContext.Current.Session;
try
{
// This is a method we created that checks if user has timed out and throws the exception if so.
SessionBuilder.Create(session, HttpContext.Current.Request, HttpContext.Current.Response);
}
catch (SessionTimeOutException e)
{
throw new WebFaultException<SessionTimeOutException>(new SessionTimeOutException(e.Message), System.Net.HttpStatusCode.BadRequest);
}
return session;
}
And here is the client-side code that handles errors in my AJAX request:
error: function (HttpRequest)
{
// This is the line that gets the exception because the responseText is a standard .NET XML error, not my custom JSON error.
var parsedReply = $.parseJSON(HttpRequest.responseText);
if (parsedReply.ClassName === "SessionTimeOutException")
{
var url = "../timeout.asp?" + parsedReply.Message;
window.location.href = url;
}
}
JavaScript has try { ... } catch(ex) { ... } also.
error: function (HttpRequest)
{
var parsedReply;
try {
parseReply = $.parseJSON(HttpRequest.responseText);
if (parsedReply.ClassName === "SessionTimeOutException")
{
var url = "../timeout.asp?" + parsedReply.Message;
window.location.href = url;
}
} catch(ex) {
parsedReply = HttpRequest.responseText;
//Do something else
}
}

What does this snippet in HTTP JSON API SERVER excercise in learnyounode

Context
I've come across excercise in learnyounode
npm install -g learnyounode
called HTTP JSON API SERVER.
Goal of an excercise:
Write an HTTP server that serves JSON data when it receives a GET request to the path '/api/parsetime'. Expect the request to contain a
query string with a key 'iso' and an ISO-format time as the value.
For example:
/api/parsetime?iso=2013-08-10T12:10:15.474Z
I wasn't able to solve it, which I think is due to lack of some specific API knowledge, so i looked up a solution, and found this (which works fine btw):
var http = require('http');
var url = require('url');
function parsetime (time) {
return {
hour: time.getHours(),
minute: time.getMinutes(),
second: time.getSeconds()
};
}
function unixtime (time) {
return { unixtime : time.getTime() };
}
var server = http.createServer(function (req, res) {
var parsedUrl = url.parse(req.url, true);
var time = new Date(parsedUrl.query.iso);
var result;
if (/^\/api\/parsetime/.test(req.url))
result = parsetime(time);
else if (/^\/api\/unixtime/.test(req.url))
result = unixtime(time);
if (result) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(result));
} else {
res.writeHead(404);
res.end();
}
})
server.listen(Number(process.argv[2]));
Actual question
I looked at this snippet and froze.
if (/^\/api\/parsetime/.test(req.url))
result = parsetime(time);
else if (/^\/api\/unixtime/.test(req.url))
result = unixtime(time);
Could anyone explain what /^\/api\/parsetime/.test(req.url) does exactly? At first it looks like some kind of regular expression, but I've never seen that RegExp could invoke methods. I guess that it is some form of identifying URL path, but guess is not worth much in industry.
Thanks everyone in advance!
It may look as if
if (/^\/api\/parsetime/.test(req.url))
result = parsetime(time);
else if (/^\/api\/unixtime/.test(req.url))
result = unixtime(time);
is invoking a function, but it is just generating a string output which the actual invoker called .test() turns into a truthful expression.
For more on javascript regex have a look at https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
The instructions say :
Write an HTTP server that serves JSON data when it receives a GET request to the path '/api/parsetime' (...) add second endpoint to the path '/api/unixtime'
which means the GET requests the server gets can be to paths other than '/api/parsetime' (resp. '/api/unixtime')
So, you want to test whether the GET request the server gets is to either of the 2 paths mentioned. And you do that with a regexp. An easy way to check the URL against the 2 URL given, is to use the test() method.
See examples of regexp on MDN :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test
In:
if (/^\/api\/parsetime/.test(req.url))
result = parsetime(time);
else if (/^\/api\/unixtime/.test(req.url))
result = unixtime(time)
The first "/" character in the if statement denotes the beginning of a regex object in JavaScript and it is ended with another "/" character. So /a/.test('a') for example would evaluate to true.
The "^" character in a regex just denotes the first character in a regex and the "\/" is because the "/" is a special character that ends the regex, and the "\" in front is another special character that cancels out special characters, so with "\/" we end up with a literal "/" as the first("^") character in our search pattern.
So in the regex above /^\/api\/parsetime/ we keep the pattern going by canceling out the "/" characters. The "^" goes in front to say we need to start with a literal "/". And then we terminate the regex as always with "/".
Regular Expressions and other special characters found here:
https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
var http = require('http')
var url = require('url')
function parsetime (time) {
return {
hour: time.getHours(),
minute: time.getMinutes(),
second: time.getSeconds()
}
}
function unixtime (time) {
return { unixtime: time.getTime() }
}
var server = http.createServer(function (req, res) {
var parsedUrl = url.parse(req.url, true)
var time = new Date(parsedUrl.query.iso)
var result
if (/^\/api\/parsetime/.test(req.url)) {
result = parsetime(time)
} else if (/^\/api\/unixtime/.test(req.url)) {
result = unixtime(time)
}
if (result) {
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify(result))
} else {
res.writeHead(404)
res.end()
}
})
server.listen(Number(process.argv[2]))

URL draft specification validate method

I've been looking at the new URL specification which is now implemented in Chrome Canary, and it looks very useful.
Is there any way to validate a URI before it is passed into the URL object?
For example
var urlToCheck = "http//www.google.com";
if(URL.isValid(urlToCheck)) {
var u = new URL(urlToCheck, baseUrl);
console.log(u.hostname);
}
I can't see anything in the linked specification doc. I would really not like to have to process the thrown Exception just to check the URI is valid.
Actually the 2-parameter version of the URL constructor accepts anything as its first parameter:
try{
new URL(null, 'http://www.example.com');
new URL({ob:'jects',even:{nested:'ones'}}, 'http://www.example.com');
new URL(['arrays'], 'http://www.example.com');
new URL(/regexes/, 'http://www.example.com');
new URL(false, 'http://www.example.com');
new URL(undefined, 'http://www.example.com');
console.log('new URL() takes any value as its first parameter!');
}catch(e){}
This means you don't have to validate both URLs; you only have to validate the base URL. Therefore a simple solution like this should suffice:
URL.isValid = function(url) {
try{
new URL(url);
} catch(e) {
return false;
}
return true;
};
You said in your comment that you can't tell if it's the base URL or the URL that's invalid so you'd rather check them both separately. If so, why not just do that? For example, something like this:
URL.isValid = function(url, base) {
if(base !== undefined) {
try {
new URL(base);
}
catch(e) {
return false;
}
}
try {
new URL(url, base);
return true;
}
catch(e) {
return false;
}
});
Lets you check both at the same time if preferred, or as you said you wanted, separately by first checking URL.isValid(base) and then checking URL.isValid(url, base). If the first check fails you know base is invalid, if the second does, you know url is invalid. If you really wanted, you could return separate error codes from .isValid based on which url was invalid.
You can use this function to validate url:
function isValidUrl(url) {
return url.match(/^(ht|f)tps?:\/\/[a-z0-9-\.]+\.[a-z]{2,4}\/?([^\s<>\#%"\,\{\}\\|\\\^\[\]`]+)?$/);
}

Categories

Resources