http url parameter Invalid Character Error - dart

I have developed a REST API using feathers.js (https://feathersjs.com/).
When trying to do a HTTP 'read' request in Flutter using package:http/http.dart I have encountered an error. The http.dart library is unable to correctly parse the query params I pass to the URI.
The error I receive through the Android Studio debug console is ;
FormatException: Invalid character (at character 84) E/flutter
(11338): ...lk.com/weatherobs?last=true&location[$in]=Bellambi&location[$in]=Nowra ....
The error is indicating the square brackets and possibly the $ sign ('[$in]' ) are the issue.
_getDemoRequest() {
String url = r"http://demoapi.ap-southeast-2.elasticbeanstalk.com/weatherobs?last=true&location[$in]=Bellambi&location[$in]=Nowra&location[$in]=Sydney Airport&location[$in]=Thredbo Top Station&location[$in]=Hobart&location[$in]=Coolangatta";
http.read(url).then(print);
}
In the URL I have tried prefixing the String with and without 'r' for a raw string to no avail.
I have also tried using httpClient with params with no success and the exact same error on the square brackets eg '[$in]'
String httpbaseUri = "http://xxxx.ap-southeast-2.elasticbeanstalk.com";
String qParams = r"?last=true&location[$in]=Bellambi&location[$in]=Nowra";
String path = "/weatherobs";
var _uri = new Uri.http(baseUri, path, qParams);
await httpClient.read(_uri, headers: {"Accept": "application/json"});
As a person with approximately 3 weeks of Flutter/Dart experience I believe its an elementary problem, but one in which several hours of research has uncovered no solution.
The ways the URI query parameters are structured (with the square brackets ie [$in]) are dictated by the feathers.js framework.
Any help would be appreciated.
It has been brought to my attention in another thread https://stackoverflow.com/questions/40568/are-square-brackets-permitted-in-urls :
That the URL Specification RFC 3986 generally does not permit square brackets in an URL.
My question was triggered as the get request works as intended in Postman, Chrome Browser and also javascript applications using axios.js, but not in an application developed in Flutter/Dart using standard http.read methods.

It doesn't look like [] are supported in the URL (except for the host IP for IPv6). See Are square brackets permitted in URLs?.
Please check if the API accepts them when they are encoded like:
void main() {
var url = r'http://demoapi.ap-southeast-2.elasticbeanstalk.com/weatherobs';
var locationKey = Uri.encodeQueryComponent(r'location[$in]');
var qParams = 'last=true&$locationKey=Bellambi&$locationKey=Nowra&$locationKey=Sydney Airport&$locationKey=Thredbo Top Station&$locationKey=Hobart&$locationKey=Coolangatta';
try {
print(Uri.parse(url).replace(query: qParams));
} catch(e) {
print(e);
}
}
DartPad example
See also api.dartlang.org/stable/1.24.3/dart-core/Uri/…

You can use this flutter package which allow you to communicate with your feathers js server from flutter app as said in: https://stackoverflow.com/a/65538226/12461921

Related

Filename with a hash (#) not uploading

I'm attempting to send a file to OneDrive using the following code:
$uri = "/me/drive/items/$folderId/children('{$fileName}')/content";
$graph = $this->graph->create($user);
$client = $this->graph->createClient();
$item = $graph->createRequest("PUT", $uri)
->attachBody($fileContent)
->setReturnType(Model\DriveItem::class)
->execute($client);
This works great if $fileName is something like Test.doc
But for some reason, when the filename has a hash (#) in the filename, then I get an error:
object(Microsoft\Graph\Model\DriveItem)#1509 (1) {
["_propDict":protected]=>
array(1) {
["error"]=>
array(3) {
["code"]=>
string(10) "BadRequest"
["message"]=>
string(36) "Bad Request - Error in query syntax."
["innerError"]=>
array(2) {
["request-id"]=>
string(36) "ff3fe15f-b1ee-4e92-8abd-2400b1c1b5cf"
["date"]=>
string(19) "2018-10-04T14:30:51"
}
}
}
Can someone possibly clarify if this is a bug or actual behaviour (i.e. you cannot have a # in a filename)
Thanks
I guess you are utilizing Microsoft Graph Library for PHP, special characters such as # needs to be escaped.
So, either replace the hash with %23 (percent encoding) or use rawurlencode function as shown below:
$fileName = rawurlencode("Guide#.docx");
$requestUrl = "https://graph.microsoft.com/v1.0/drives/$driveId/root:/$fileName:/content";
try {
$item = $client->createRequest("PUT", $requestUrl)
->attachBody($fileContent)
->setReturnType(Model\DriveItem::class)
->execute();
} catch (\Microsoft\Graph\Exception\GraphException $ex) {
print $ex;
}
Although the file name have support # in name, but it doesn't mean the Product Team provide the API or adjust the existing API first time, the API you use may not have fully adjusted to suit thore latest naming rules. So it should be actual behavior now but not bug/or you can treat it as none-existed feature.
There are a related issue in the SharePoint dev issue list, although they aren't same one, but the suggestion is the same, vote the exising feature or submit an new one on UserVoice.

HttpContent.ReadAsStringAsync throws when charset is surrounded by quotes

I am trying to POST files containing arbitrary binary data to a WebAPI 2 controller as multipart/form-data.
When trying to read the files using the following:
var provider = new MultipartFormDataStreamProvider(uploadDirectoryPath);
await Request.Content.ReadAsMultipartAsync(provider);
I get:
System.InvalidOperationException: The character set provided in ContentType is invalid.
Cannot read content as string using an invalid character set.
---> System.ArgumentException: '"utf-8"' is not a supported encoding name.
For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
Parameter name: name
I understand that the problem is the quotes around utf-8 and it is this bug in HttpContent.ReadAsStringAsync() used internally as explained here.
The request is being sent from a Unity3D app and I am unable to change the charset in the request body.
Here is the code I am using in the Unity3D script to create the POST request.
WWW chunkFile = new WWW("file:///" + Path.Combine(tempZipFolderPath, chunkFilenames[j]));
yield return chunkFile;
if (chunkFile.error != null)
throw new Exception(string.Format("{0} error opening file {1}", chunkFile.error, chunkFilenames[j]));
//BUGFIX: Not using IMultipartFormSection because of https://fogbugz.unity3d.com/default.asp?826626_htlchp13nh8th2to
var form = new WWWForm();
form.AddField("chunkNumber", chunkNumber);
form.AddField("totalChunks", totalChunks);
form.AddField("identifier", tempZipFileName);
form.AddBinaryData("filename", chunkFile.bytes, chunkFilenames[j]);
var scanUploadPostRequest = UnityWebRequest.Post(WebApiScanUploadUrl, form);
yield return scanUploadPostRequest.Send();
//BUGBUG: charset UTF-8 wrapped in quotes causes error
Is there a workaround to this?

How to prevent xss

this is my native url:
127.0.0.1//myweb/home.php?u=daniel
now when I include this type of xss:
127.0.0.1//myweb/home.php/"><script>alert('hacked')</script>?u=daniel
it now appears to be hacked, how can I avoid this type XSS attack ?
ADDED
Here is the other codes: (I do not add the fetching the users the data)
require_once 'core/init.php';
$currentUser = new User();
$report = null;
if(!$currentUser->isLoggedIn()) {
Redirect::to('index.php');
}
You can always use php to filter away all the unnecessary part of the url.
This is your web site so you know what character is useless in your web site.
For example, I know that in my web site, the double quotes/" character is useless in my web site.
So, I can straight away filter out any part with double quotes/" character.
You can get your current url from the following code.
$url = $_SERVER['REQUEST_URI']
Then, you just ignore anything after double quotes character by using explode.
$safe_url = explode("\"", $url);
So, you will just use $safe_url[0] as your url.

How make WCF allow dots(.) in url?

I use WCF and have a method like this:
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "LoadProducts/{key}/{price}")]
XmlDocument LoadProducts(string key, string price= null);
price is string, inside LoadProducts I will try to parse it from string to double and do my other operations.
But in url, I can not get request any parameter for price like '24.25', '0.253' etc. It does not allow any value with dot.
localhost:13448/RestService.svc/LoadProducts/null/41.145
I get error "Please review the following URL and make sure that it is spelled correctly. "
How can I solve this?
Dots already have a meaning in a URL, they separate the target hostname, IP address or in the path they separate the resources from its extension. You will need to URL encode your request URL.
In .NET there is a method called UrlEncode to help you encode URLs. It is:
string url = "http://localhost/MyService/MyKey/24.25";
string encodedUrl = HttpUtility.UrlEncode(url);
Check out the MSN documentation for UrlEncode for more details.
I solved my issue. I switched server from Visual Studio Development Server to Local IIS Web Server, url took dot symbol inside parameter.

QuickBooks Online querying with filter returns 401 everytime

I've had success creating objects with POST and Content-Type application/xml
I've also had success querying using Content-Type application/x-www-form-urlencoded with a blank request body which returns all of the object type depending on which URI I specify.
I can also get the same to work with something like PageNum=1&ResultsPerPage=1 in the request body and I have figured out how to incorporate that into the signature so I get a valid response.
However no matter how I format it, I cannot get anything other than a 401 response when I try to use a filter (something basic like Filter=FAMILYNAME :EQUALS: Doe). I've read over the OAuth Core 1.0 Revision A specifications on how all parameter names and values are escaped using the [RFC3986] percent-encoding. However I feel like I'm missing a step or formatting incorrectly. I've seen inconsistent information in my searching through Intuit's forums on what exactly is the proper format.
Any help on this would be greatly appreciated. I've been struggling with this for a good week now.
The response I get when trying to use a filter is:
HTTP Status 401 - message=Exception authenticating OAuth; errorCode=003200; statusCode=401
----Update----
I'm am seeing the same error when I try to use filters with the New IPP Developer Tools - IPP API Explorer. I'm using the IDS V2 QBO API Explorer. I'm able to use that tool to do a retrieve all Post and the response shows all of my customers, but when I try to use a filter I get :
Server Error
401 - Unauthorized: Access is denied due to invalid credentials.
You do not have permission to view this directory or page using the credentials that you supplied.
Any Ideas? If I'm getting the same error from the API Explorer tool, it makes me think the problem is something else entirely.
----Final Update----
I have finally had success with filters and I believe I have figure out what my problem was. I was always suspicious that I was able to get queries with pagination like "PageNum=1&ResultsPerPage=1" to work, but could not get something like "Filter=FAMILYNAME :EQUALS: Doe". I suspected there problem was with the white space in the filter format. What threw me off tracking this down earlier was that I could not get the filters to work in the IDS V2 QBO API Explorer. That made me suspect there was something else going on. I decided to ignore the API Explorer all together and focus on why I could get it to work the one way but no the other.
I believe my problem came down to improper encoding of the Filter's value in the signature. That explains the 401 invalid signature errors I was getting.
"Filter=Name :EQUALS: Doe" becomes "Filter=Name%20%3AEQUALS%20%3ADoe" after normalization.
Percent-Encoding that should give "Filter%3DName%2520%253AEQUALS%2520%253ADoe".
In essence you have to "double" encode the blank space and the colons, but not the equal sign. I tried many permutations of doing the encoding, but believe my mistake was that I was either not "double" encoding, or when I was double encoding I was including the '=' sign. Either way breaks your signature. Thanks for everyone's input.
I believe my problem came down to improper encoding of the Filter's value in the signature. That explains the 401 invalid signature errors I was getting.
I used an online tool to take me through the steps in properly signing an Oauth request. While going through those steps I realized my problem was with the steps where you normalize the request parameters and then percent-encode them. I was including the '=' of the filter in the normalization step, which breaks your signature. The tool I used can be found at:
http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-iv-signing-requests/
Thanks for everyone's input.
Do you get a 401 with the same request in the API Explorer?
http://ippblog.intuit.com/blog/2013/01/new-ipp-developer-tool-api-explorer.html
Also, are you using the static base URL or retrieving it at runtime?
https://ipp.developer.intuit.com/0010_Intuit_Partner_Platform/0050_Data_Services/0400_QuickBooks_Online/0100_Calling_Data_Services/0010_Getting_the_Base_URL
If you are using the static base URL, try switching to the runtime base URL to see if you still get the error.
peterl answered one of my questions on here that may also answer yours. I had been trying to put the Filters in the body when they should have gone into the header. Here was peterl's code sample for getting all unpaid invoices (open balance greater than 0.00) for a particular customer.
http://pastebin.com/raw.php?i=7VUB6whp
public List<Intuit.Ipp.Data.Qbo.Invoice> GetQboUnpaidInvoices(DataServices dataServices, int startPage, int resultsPerPage, IdType CustomerId)
{
StringBuilder requestXML = new StringBuilder();
StringBuilder responseXML = new StringBuilder();
var requestBody = String.Format("PageNum={0}&ResultsPerPage={1}&Filter=OpenBalance :GreaterThan: 0.00 :AND: CustomerId :EQUALS: {2}", startPage, resultsPerPage, CustomerId.Value);
HttpWebRequest httpWebRequest = WebRequest.Create(dataServices.ServiceContext.BaseUrl + "invoices/v2/" + dataServices.ServiceContext.RealmId) as HttpWebRequest;
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
httpWebRequest.Headers.Add("Authorization", GetDevDefinedOAuthHeader(httpWebRequest, requestBody));
requestXML.Append(requestBody);
UTF8Encoding encoding = new UTF8Encoding();
byte[] content = encoding.GetBytes(requestXML.ToString());
using (var stream = httpWebRequest.GetRequestStream())
{
stream.Write(content, 0, content.Length);
}
HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
using (Stream data = httpWebResponse.GetResponseStream())
{
Intuit.Ipp.Data.Qbo.SearchResults searchResults = (Intuit.Ipp.Data.Qbo.SearchResults)dataServices.ServiceContext.Serializer.Deserialize<Intuit.Ipp.Data.Qbo.SearchResults>(new StreamReader(data).ReadToEnd());
return ((Intuit.Ipp.Data.Qbo.Invoices)searchResults.CdmCollections).Invoice.ToList();
}
}
protected string GetDevDefinedOAuthHeader(HttpWebRequest webRequest, string requestBody)
{
OAuthConsumerContext consumerContext = new OAuthConsumerContext
{
ConsumerKey = consumerKey,
ConsumerSecret = consumerSecret,
SignatureMethod = SignatureMethod.HmacSha1,
UseHeaderForOAuthParameters = true
};
consumerContext.UseHeaderForOAuthParameters = true;
//URIs not used - we already have Oauth tokens
OAuthSession oSession = new OAuthSession(consumerContext, "https://www.example.com",
"https://www.example.com",
"https://www.example.com");
oSession.AccessToken = new TokenBase
{
Token = accessToken,
ConsumerKey = consumerKey,
TokenSecret = accessTokenSecret
};
IConsumerRequest consumerRequest = oSession.Request();
consumerRequest = ConsumerRequestExtensions.ForMethod(consumerRequest, webRequest.Method);
consumerRequest = ConsumerRequestExtensions.ForUri(consumerRequest, webRequest.RequestUri);
if (webRequest.Headers.Count > 0)
{
ConsumerRequestExtensions.AlterContext(consumerRequest, context => context.Headers = webRequest.Headers);
if (webRequest.Headers[HttpRequestHeader.ContentType] == "application/x-www-form-urlencoded")
{
Dictionary<string, string> formParameters = new Dictionary<string, string>();
foreach (string formParameter in requestBody.Split('&'))
{
formParameters.Add(formParameter.Split('=')[0], formParameter.Split('=')[1]);
}
consumerRequest = consumerRequest.WithFormParameters(formParameters);
}
}
consumerRequest = consumerRequest.SignWithToken();
return consumerRequest.Context.GenerateOAuthParametersForHeader();
}
You can also see my original Question Here on StackOverflow: Query for All Invoices With Open Balances using QuickBooks Online (QBO) Intuit Partner Platform (IPP) DevKit.

Resources