What kinds of things can cause ngSanitize to throw a Parse Error - angularjs

I have an AngularJS app that parses HTML which largely comes from emails. In some cases data-bind-html will throw a Parse Error but not all cases. I've been unable to determine why.
Does anyone know some types of tokens or syntax that can cause the error?
Here's a sample of a file which trips it up:
,
I received the following error message...:
------------------------------------------------------------------------ The server encountered an unexpected condition that prevented it from
fulfilling the request.
HTTP_Status = 500 (Internal Server Error)
URL =
----------------------------------------- Request Headers
----------------------------------------- POST /ss/servlet/FooServlet/ HTTP/1.1 Accept: Accept: / Host: mydomain.org Content-Length: 141
User-Agent: FooBar/2.1.94 Pragma: no-cache Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded; charset="utf-8"
Connection: Keep-Alive Cookie:
BIGipServerpool_cookie_apps_ss_8188=rd860o00000000000000000000ffff0a0ad0aco8188;
JSESSIONID=5215F941A173B6127E9A95B3E99E3A74
----------------------------------------- Response Headers
----------------------------------------- HTTP/1.1 500 Internal Server Error Server: Apache-Coyote/1.1 Set-Cookie:
JSESSIONID=A9B7C98E5359D961DC8958F87CCCF49E; Path=/ss
Content-Disposition: attachment; filename="spreadsheet.csv"
Content-Description: spreadsheet.csv Content-Transfer-Encoding: binary
Content-Type: application/csv;charset=ISO-8859-1 Transfer-Encoding:
chunked Date: Wed, 06 Mar 2013 18:46:19 GMT Connection: close
-------------...

Emails can contain a lot of arbitrary encoding and invalid HTML, such as <email#domain.com>. To eliminate the Parse Errors I've implemented my own filter which takes effect before it goes through ngSanitize/bind-html.
ng-bind-html="obj.emailContent | sanitizeEmail"
myModule.filter('sanitizeEmail', function() {
return function(input) {
return input.replace(/<[\w-]*\.[\w-]*>/g, '').replace(/<[\w\.\$-]+[\:#].*>/g, '');
};
});

Related

Gatling - extract token from response headers

I'm a newer in Gatling and I created a POST login request which returns the following response headers:
HTTP/1.1 302
Set-Cookie: JSESSIONID=ECA5F6FEA172B13BF5D445399C9C0962; Path=/; HttpOnly
Location: http://localhost:20001/index;jsessionid=ECA5F6FEA172B13BF5D445399C9C0962
Content-Language: en-US
Content-Length: 0
Date: Thu, 06 May 2021 16:01:20 GMT
I need to extract JSESSIONID value and use it in other requests.
I tried:
.check(regex("JSESSIONID=(.*?);").find.saveAs("token")))
however got an error
> regex(JSESSIONID=(.*?);).findAll.exists, found nothing 1 (100.0%)
Any help would be greatly appreciated!
You need use headerRegex
.check(headerRegex("Set-Cookie", """JSESSIONID=(.*?);"""").saveAs("token"))

Gatling. How to send POST multipart/form-data without file

I try to send POST multipart/form-data but without attached file. It's like the client sends sign up form with email + password and without avatar file(this field isn't required).
HTTP request:
POST https://.../profile/user/own
headers=
Authorization: bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIwN2NjMDUzYS0wMTczLTExZWItOWI1OC0wMTg4NjFhYmViYjAiLCJzY29wZSI6WyJjbGllbnQiXSwiZXhwIjoxNjAxMzc0MzEzLCJ1dWlkIjoiMDdjYzA1M2EtMDE3My0xMWViLTliNTgtMDE4ODYxYWJlYmIwIiwiYXV0aG9yaXRpZXMiOlsiUGF5bWVudE1hcmtldENsaWVudCIsImxvYmJ5X2NoYXQiLCJVc2VyQmFsYW5jZSIsInVzZXItc2xvdC1yZWFkIiwibGVhdmVfY2FsbCIsInJlYWRfc2NoZWR1bGVfdXNlciIsInVzZXItY2FuY2VsLXNsb3QiLCJyZWFkX3VzZXJfcXVlc3Rpb25uYWlyZSIsIndyaXRlX3RpbWV6b25lIiwicmVhZF90aGVyYXBpc3RzX2luZm8iLCJlbmRfc2Vzc2lvbiIsImpvaW5fY2FsbCIsImVkaXRfdXNlciIsImFuc3dlcl9hY3Rpb24iLCJyZWFkX3Nlc3Npb24iLCJQYXltZW50VmVyaWZpQ2xpZW50IiwiYmVnaW5fc2Vzc2lvbiIsIm9jY3VweS1zbG90Iiwid3JpdGVfbWVzc2FnZSIsInJlYWRfdXNlciIsInJlYWRfY29udmVyc2F0aW9uIiwicmVhZF9jaGF0IiwicmVhZF9jdXJyZW50X2NoYXQiLCJzb2NrZXQiLCJtYWtlX2NhbGwiLCJyZWFkX2NhbGwiLCJyZWFkX21lc3NhZ2UiLCJjYWxsX3Rva2VuIl0sImp0aSI6Ijg1NjQ5MmJhLTI0ODUtNDAyZC1hZTJhLWZiY2E2YjhkNGY2MSIsImNsaWVudF9pZCI6ImNsaWVudCJ9.APWse9P8SIJtDMMay8UTT9CN_JEvSIRaznn8JALcYfxz107IaL5ezwEJfIEDBb9_WEDeVKvpjI1eUmiYBQiOcF5LkIPhpww_8vaSbWvWP3Tkg21QQceNEZwnjucMc6Doj1YNlx3iOs03Mv8zmOJZ2S1acz5sVj5cK_ufrItG7Ic_-bbpW67Byl1vNgbTgaJoGMRAgqfCxKpAVpxMFqNw3F8FMKe0dm-uYmJwpKlWVg4sEUOW7LSZ6wr3c5XgBHXVvTzVFb0sJyhFkw9W1nrMSJTxJqsaVGEzIe01qhQZasbRkMxC32XXlFzpGSmBDJpdWpTD3pUXrIhD4v15PWt3wg
accept: */*
host: api.dev.psychicbook.net
content-type: multipart/form-data
content-length: 108
formBody=
userData: {"email":"automation.tku1fin9av3#test.com","nickname":"5SkHTB0EVs"}
=========================
HTTP response:
status=
500
headers=
Server: nginx/1.17.10
Date: Mon, 28 Sep 2020 10:11:53 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
X-Application-Context: gateway-service:develop:8765
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Strict-Transport-Security: max-age=15724800; includeSubDomains
body=
{"timestamp":1601287913987,"status":500,"error":"Internal Server Error","exception":"org.springframework.web.multipart.MultipartException","message":"Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found","path":"/profile/user/own"}
There is a special method for file uploading -> .formUpload("file", "image.jpg"), but I don't want to send any file.
If I make the same with Insomnia or anoter REST client, everything is OK, and it looks like:
HttpResponse<String> response = Unirest.post("https://.../profile/user/own")
.header("authorization", "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJjMGRlNWI3ZS0wMTYzLTExZWItOWI1OC0wMTg4NjFhYmViYjAiLCJzY29wZSI6WyJjbGllbnQiXSwiZXhwIjoxNjAxMzY3NzUyLCJ1dWlkIjoiYzBkZTViN2UtMDE2My0xMWViLTliNTgtMDE4ODYxYWJlYmIwIiwiYXV0aG9yaXRpZXMiOlsiUGF5bWVudE1hcmtldENsaWVudCIsImxvYmJ5X2NoYXQiLCJVc2VyQmFsYW5jZSIsInVzZXItc2xvdC1yZWFkIiwibGVhdmVfY2FsbCIsInJlYWRfc2NoZWR1bGVfdXNlciIsInVzZXItY2FuY2VsLXNsb3QiLCJyZWFkX3VzZXJfcXVlc3Rpb25uYWlyZSIsIndyaXRlX3RpbWV6b25lIiwicmVhZF90aGVyYXBpc3RzX2luZm8iLCJlbmRfc2Vzc2lvbiIsImpvaW5fY2FsbCIsImVkaXRfdXNlciIsImFuc3dlcl9hY3Rpb24iLCJyZWFkX3Nlc3Npb24iLCJQYXltZW50VmVyaWZpQ2xpZW50IiwiYmVnaW5fc2Vzc2lvbiIsIm9jY3VweS1zbG90Iiwid3JpdGVfbWVzc2FnZSIsInJlYWRfdXNlciIsInJlYWRfY29udmVyc2F0aW9uIiwicmVhZF9jaGF0IiwicmVhZF9jdXJyZW50X2NoYXQiLCJzb2NrZXQiLCJtYWtlX2NhbGwiLCJyZWFkX2NhbGwiLCJyZWFkX21lc3NhZ2UiLCJjYWxsX3Rva2VuIl0sImp0aSI6Ijg5ZDg4OTViLTU1NzQtNDk2OC1hNmJhLWRmZjcyYmIxYWI1MyIsImNsaWVudF9pZCI6ImNsaWVudCJ9.bW7F65elarJNQ9RkfIJcH0uq9Og0ue8TXNZ7Gh_FFCdj_c8SVHlPXwu-nEoZZSTVk3gBB2I_hw8MqPfCZVZrlAlzyIfAcyuQ1WRgRH5-xVzYej3XqBEADuCjBabcO87LoPwz_vYCT3JZVhNZHcDMOkQ429dg0HdKeSBd6qJaPYCgWgq529b9-wnufNBx9LHyaTYLWZC5nMfmDbyep3sc2_q6YzqKMMH5a-s1SmOgQpKbCNyCx7gui3tiYqQh21zMN-PhtkRNAD78awzpIpZhuZTF-AbrQkI6J1Yvsg59AYkZZVBd5gyCSopydquezf7xaAc3Ot2L-DubGzWwr2u9gA")
.header("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"userData\"\r\n\r\n{\"email\":\"automation.tku1fin9av3#test.com\",\"nickname\":\"qatest5\"}\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")
.asString();
How can I make the same but with Gatling?
I had the same issue. I have some entries with, and some without files. Both need to be uploaded using body parts.
When i set one fields using StringBodyPart it worked for me:
val uploadDocument = doIfEqualsOrElse(session => session("file").as[String], "") {
// executed if the session value stored in "myKey" starts with "admin"
exec(
http("upload: ${title}")
.post(
clientPortalUrl + "/customerportal/api/documents"
)
.headers(multipartUploadHeaders)
//if we do not call formUpload() we need set one field using StringBodyPart, the rest will follow.
.bodyPart(StringBodyPart("title", "${title}")).asMultipartForm
.formParam("documentType", "${documentType}")
.formParam("accountId", "${accountId}")
.formParam("period", "${period}")
.formParam("endDate", "${endDate}")
.formParam("signer", "${signer}")
.formParam("nexusRecipient", "${nexusRecipient}")
.formParam("vatFiscalEntityDivision", "${vatFiscalEntityDivision}")
.formParam("editor", "${editor}")
.formParam("repeatable", "${repeatable}")
.requestTimeout(5.minutes)
.check(status.is(201))
.check(jsonPath("$.title").exists)
)
} {
exec(
http("upload: ${title}")
.post(
clientPortalUrl + "/customerportal/api/documents"
)
.headers(multipartUploadHeaders)
.formParam("title", "${title}")
.formParam("documentType", "${documentType}")
.formParam("accountId", "${accountId}")
.formParam("period", "${period}")
.formParam("endDate", "${endDate}")
.formParam("signer", "${signer}")
.formParam("nexusRecipient", "${nexusRecipient}")
.formParam("vatFiscalEntityDivision", "${vatFiscalEntityDivision}")
.formParam("editor", "${editor}")
.formParam("repeatable", "${repeatable}")
.formUpload("files[]", "${file}")
.requestTimeout(5.minutes)
.check(status.is(201))
.check(jsonPath("$.title").exists)
)
}

Missing Csrf token cookie

I'm relatively new to CakePHP (v3.7). I have an application in which I'm getting a "Missing Csrf Token Cookie" error.
In Application.php, I have:
$options = []; // I'm fine with the default options.
$csrf = new CsrfProtectionMiddleware($options);
$middlewareQueue->add($csrf);
The form page has a hidden form element with the _csrfToken in it.
I'm confused as to why it's not being found on the POST?
Digging further, I found that in CsrfProtectionMiddleware.php, the _validateToken() function below behaves as follows:
$cookies is null (there are no cookies set.)
thus, $cookie is null.
$post actually contains the content of the _csrfToken parameter from the hidden parameter on the page. However the function never looks at it. Because $cookie is null,
the if(!$cookie) statement causes an InvalidCsrfTokenException to be thrown.
protected function _validateToken(ServerRequest $request)
{
$cookies = $request->getCookieParams();
$cookie = Hash::get($cookies, $this->_config['cookieName']);
$post = Hash::get($request->getParsedBody(), $this->_config['field']);
$header = $request->getHeaderLine('X-CSRF-Token');
if (!$cookie) {
throw new InvalidCsrfTokenException(__d('cake', 'Missing CSRF token cookie'));
}
if (!Security::constantEquals($post, $cookie) && !Security::constantEquals($header, $cookie)) {
throw new InvalidCsrfTokenException(__d('cake', 'CSRF token mismatch.'));
}
}
}
Obviously, the middleware is expecting an actual cookie, in addition to a hidden parameter. Where is this cookie set (or supposed to be set?)
Update:
I checked on the browser side. The cookie is being set, but the browser isn't returning it on the POST request.
Here's CakePHP's RESPONSE to the original GET request to populate the page:
Connection: Keep-Alive
Content-Length: 3013
Content-Type: text/html; charset=UTF-8
Date: Wed, 08 May 2019 23:07:31 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.33 (Unix) PHP/7.1.1
Set-Cookie: csrfToken=b553dd2e06e57f6d514ee41a120e1c60084adafddfbaa6f72db1f7f590fcf50143876ac817d29d6f1cf9a786031d6235ba21e265b9d3b2a0ee4535854f048b66; path=/webroot/
X-Powered-By: PHP/7.1.1
Note the csrfToken cookie.
... and here's the POST that the browser sends back with the form data
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 184
Content-Type: application/x-www-form-urlencoded
DNT: 1
Host: *************
Origin: ****************
Pragma: no-cache
Referer: ***************
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36
Query String Parameters
redirect: /Users/login
Form Data
_method: POST
_csrfToken: b553dd2e06e57f6d514ee41a120e1c60084adafddfbaa6f72db1f7f590fcf50143876ac817d29d6f1cf9a786031d6235ba21e265b9d3b2a0ee4535854f048b66
username: xxxxxxxxxx
password: xxxxxxxxxx
Note that it's sending back the hidden form parameter _csrfToken, but NOT the cookie.
Thanks for any help...
This turned out to be a problem with the DOCUMENT_ROOT directory setting in Apache. It was set to the parent directory of webroot, instead of to webroot itself. When I changed it everything worked.

Angular $http doesn't turn all response headers

I would like to get the 'X-Total-Count' response header of a RESTful API. While trying to get the header in the query callback function of my ngResource 'User', it seems that $http ignores a lot of the reponse headers.
These are the response headers of my request:
Access-Control-Allow-Origin: *
Cache-Control: max-age=0, private, must-revalidate
Connection: close
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Fri, 17 Oct 2014 11:13:26 GMT
Link: <http://xxxx.xxx/user?page=2>; rel="next"
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Total-Count: 32
Here I'm querying the set of users:
User.query({
page: $scope.pagingOptions.currentPage,
limit: $scope.pagingOptions.pageSize
}, function(users, responseHeaders) {
console.log(responseHeaders());
console.log(responseHeaders('X-Total-Count'));
});
That's the result of the console:
Object { cache-control="max-age=0, private, must-revalidate", content-type="application/json; charset=utf-8"}
null
So why the $http's responseHeaders() function turns only 2 of 10 header properties?
Are you sure you are not doing cross origin resource sharing?
see 7.1.1 Handling a Response to a Cross-Origin Request
That specification forbids access to any response header field other
except the simple response header fields (i.e. Cache-Control,
Content-Type, ...)

setting a Content-Type in CakePHP when the response is large-ish (>4kB)

Quite simply, I'm trying to generate and download a CSV file from a CakePHP controller. No problem generating the CSV, and everything works until the response >= 4096 bytes.
The following controller illustrates the problem:
class TestTypeController extends Controller {
public function csv($size = 100) {
# set the content type
Configure::write('debug', 0);
$this->autoRender = false;
$this->response->type('csv');
# send the response
for ($i = 0; $i < $size; $i++)
echo 'x';
}
}
When I call http://baseurl/test_type/csv/4095, I'm prompted to save the file, and the Content-Type header is text/csv. The response headers are:
HTTP/1.1 200 OK
Date: Tue, 05 Jun 2012 14:28:56 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.1
Content-Length: 4095
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Content-Type: text/csv; charset=UTF-8
When I call http://baseurl/test_type/csv/4096, the file is printed to the screen, and the response headers are:
HTTP/1.1 200 OK
Date: Tue, 05 Jun 2012 14:28:53 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.1
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 38
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
Obviously, 4kB is the limit where Content-Encoding starts gzipping the response. I'm not familiar with how the Content-Type is meant to react, but I'd obviously prefer it to remain text/csv.
The same problem occurs using the RequestHandlerComponent to manage the type of the response.
I'm using the CakePHP 2.2.0-RC1, but I've verified the problem exists with stable 2.1.3. Any ideas? Pointers in the right direction?
The answer was pretty simple -- the controller should be returning the CSV data instead of echoing it.

Resources