AFNetworking 404 response for valid url - afnetworking

I'm using AFNetworking 2.0 accessing (AFHTTPRequestOperation *) GET for a multiplicy of URLs for public web sites. 99% of the calls work fine but the odd one returns 404 (Not Found). An example is URLString = "http://feeds.wired.com/wired/index" which works (without a redirect) with all of the following methods:
Browser
Low-level iOS call [NSURLConnection sendAsynchronousRequest:URLString ...] from Objective-C code
$.ajax call via jQuery from JavaScript
However, (AFHTTPRequestOperation *) GET returns 404 (without a redirect).
These are the headers I'm sending for both (AFHTTPRequestOperation *) GET and $.ajax (NSURLConnection works without any headers at all).
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko
Accept: text/html, application/xhtml+xml, /
Accept-Encoding: gzip, deflate
DNT: 1
Cache-Control: no-cache
I'm quite sure there is something weird with the response from http://feeds.wired.com/wired/index which either AFNetworking or some lower level iOS NS method is choking on but I can't figure it out from rudimentary profiling of the code execution.
I'd like AFNetworking to be flexible enough to handle anything I throw at it that browsers, low-level iOS and jQuery $.ajax can handle.
Does anyone know the potential source of this issue and how AFNetowking could be parameterized of modifed to accomodate it?

I have discovered the problem here. If (AFHTTPRequestOperation *) GET is provided a value for "parameters" that is an empty dictionary, it appends a "?" to the end of the URL which some websites don't like and respond to with "404". The solution is to never provide an empty dictionary. Instead, provide "nil" if there are no parameters.
Personally I think this is an AFNetworking bug, but the workaround is simple.

Related

How can I stop sending a preflight request on a redirect?

I discovered that six years ago, the previous developer commented out this line of code (Ruby, Rails):
#protect_from_forgery
I replaced it with the default:
protect_from_forgery with: :exception
and now I mysteriously get the following error when I try to add items to my cart while logged out:
Access to XMLHttpRequest at 'https://id.foo-staging.com/openid/checklogin?return_to=http%3A%2F%2Flocalhost.foo-staging.com%3A3000%2Fcart%2Fitems' (redirected from 'http://localhost.foo-staging.com:3000/cart/items') from origin 'http://localhost.foo-staging.com:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
I've pinned down that this is happening because of the following lines:
def get_user_identity_from_open_id_server
redirect_to "#{OPEN_ID_PROVIDER_URL}/openid/checklogin?return_to=#{Rack::Utils.escape(request.url)}"
end
def open_id_authentication
#stuff
get_user_identity_from_open_id_server
end
before_filter :open_id_authentication
I understand what causes a preflight request, at a very high level, thanks to the documentation. But I don't think I'm doing any of those things.
* the request method is anything other than GET, HEAD, or POST
* you’ve set custom request headers other than Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, or Width
* the Content-Type request header has a value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain
So my initial question is how do I determine what is triggering the preflight request, and then maybe I can figure out how to prevent it from happening. Is this a situation that I can change on my end, or does something need to change on id.foo-staging.com (which I don't have access to, but could probably ask the right person to fix it for me).
I've been Googling all day, and nothing seems to make any sense to me, especially because I can't pin down precisely what's wrong.
I can solve the issue with this code:
skip_before_filter :open_id_authentication, :only => [:create], :if => :current_user and :anonymous_cart
But I have to assume that this is unsafe, from a security standpoint?
ETA: This is what I see on the Network tab for this request:
General:
Request URL: https://id.foo-staging.com/openid/checklogin?return_to=http%3A%2F%2Flocalhost.foo-staging.com%3A3000%2Fcart%2Fitems
Referrer Policy: no-referrer-when-downgrade
Request Headers:
Provisional headers are shown
Access-Control-Request-Headers: x-requested-with
Access-Control-Request-Method: GET
Origin: http://localhost.foo-staging.com:3000
Referer: http://localhost.foo-staging.com:3000/p/Product0/1?id=1&slug=Product0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Query String Parameters:
return_to: http://localhost.foo-staging.com:3000/cart/items
I presume the problem is the x-requested-with request header. But I don't know how to resolve this.
EATA:
Many JavaScript frameworks such as JQuery will automatically send this header along with any AJAX requests. This header cannot be sent cross-domain:
I guess my only option is to figure out how to rewrite this without AJAX?
To avoid the preflight request you have to remove x-requested-with header but the error that you have is because the response location in the preflight call is different from the Origin.
To fix the problem, update your code to use the new URL as reported by the redirect, thereby avoiding the redirect.

API Endpoint only allows GET when it should take POST

I am building a React.js front-end portion of a web application using an already existing back-end that is built with ASP.NET MVC Framework. The method in the API's controller is named Post (which should default it to a post method) and even has the [HttpPost] decorator. I have recently enabled CORS, but I am not sure if that matters.
The API also has Swagger (it's like postman if you haven't used it before) enabled, and when I call the method as POST from the swagger, it will work and return the correct data.
However, when I try to call the method from my UI component, the API endpoint will give a 405 Method Not Allowed status code.
It says that the method only allows GET, which is baffling since it is supposed to only allow POST and it works that way on swagger or if I manually travel to the URL using a browser. Has anyone had a problem like this using React components or working with ASP.NET MVC/Web API 2?
I am completely stuck...
EDIT:
I am adding the API's method for the post endpoint.
[Route("{id}/merchant/SearchMerchants")]
[HttpPost]
[AuthorizeUserPermissionsToken(Cookie)]
public Response Post(Request rq)
{ // I put a breakpoint here to debug
// some code
}
I had to redact a lot of the code but here is the post method.
But I don't think it has to do with the API endpoint.
This is because when I debug, it will not even reach the breakpoint or call the method at all, when I am using the UI. However, it will reach the breakpoint when I travel to the endpoint on the browser or use swagger.
EDIT 2:
EDIT 3: (removed EDIT 2 and moved the original headers to bottom to reduce confusion)
Pre-flight OPTIONS request headers
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host: *redacted domain*
Origin:http://localhost:49702
Pragma:no-cache
Referer:http://localhost:49702/FindMerchants
User-Agent:Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Mobile Safari/537.36
response headers to OPTIONS request:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Origin:http://localhost:49702
Allow:OPTIONS, TRACE, GET, HEAD, POST
Content-Length:0
Date:Mon, 07 Aug 2017 18:41:42 GMT
Public:OPTIONS, TRACE, GET, HEAD, POST
Server:Microsoft-IIS/10.0
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
then the real POST request headers after pre-flight:
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:154
Content-Type:application/json
Cookie: *redacted a bunch of cookies*
Host:a *redacted domain*
Origin:http://localhost:49702
Pragma:no-cache
Referer:http://localhost:49702/FindMerchants
User-Agent:Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Mobile Safari/537.36
The real response headers are like so:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Origin:http://localhost:49702
Allow:GET
Cache-Control:no-cache
Content-Length:73
Content-Type:application/json; charset=utf-8
Date:Mon, 07 Aug 2017 17:58:28 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/10.0
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
EDIT 4:
Request URL:*redacted domain*/380/merchant/SearchMerchant
Request Method:POST
Status Code:405 Method Not Allowed
Remote Address:127.0.0.1:80
Referrer Policy:no-referrer-when-downgrade
EDIT #9999 (jk):
My react component simply calls a custom data service that I wrote, which has a post method like this.
post(relativeUrl, data, apiVersion) {
var url = this.getUrl(relativeUrl, apiVersion);
var res = $.ajax({
type: 'POST',
url: url,
contentType: 'application/json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
data: JSON.stringify(data)
});
return res;
}
I simply pass relativeUrl to fetch a list related to a user account.
Before I make a call that fails (which shows 405), I use this same method to log in and update the global redux state for the app. After updating the global state, I render a different component and use this method again with another relativeUrl to fetch the list. Then I get the error. I also make sure that the login call is finished and returns and updates the state correctly before moving on.
To follow my comment,
in web.config file:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS, HEAD" />
</customHeaders>
</httpProtocol>

AFNetworking POST being sent as GET

Please excuse me if this is normal, but I am attempting to send a post request from iOS using AFNetworking. Using Charles to monitor the request, I see that a GET is sent:
GET /api/updateTeamAlert/ HTTP/1.1
Host: www.******r.co
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en;q=1, fr;q=0.9, de;q=0.8, ja;q=0.7, nl;q=0.6, it;q=0.5
Connection: keep-alive
User-Agent: ****** Alerts/1.0 (iPhone Simulator; iOS 6.1; Scale/2.00)
Is this normal? I am trying to find out why my POST parameters are empty at the server - could this be the cause?
I am creating my request like this:
NSDictionary *params = #{#"device_id":#"test-device", #"innings":#6, #"team":#"WashingtonNationals"};
[_client postPath:#"updateTeamAlert"
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *responseStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Request Successful, response '%#'", responseStr);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
UPDATE
Well, all I had to do to get this working was change the postPath to include the trailing '/' - perhaps this is obvious to most, but I would love an explanation for the accepted answer.
Well, all I had to do to get this working was change the postPath to include the trailing '/' - perhaps this is obvious to most, but I would love an explanation for the accepted answer.
PHP applications often have misconfigured servers that lose information (like HTTP method) when doing a redirect. In your case, adding the / resolved to the canonical path for your particular web service, but in redirecting to that endpoint, the POST was changed into a GET.
Another way to potentially solve this issue is to use AFURLConnectionOperation -setRedirectResponseBlock, and ensure that the redirect request has the correct verb.
#mattt's answer above is incorrect.
HTTP/1.0 302's worked as you'd logically expect "POST /FOO" 302'd to /BAR implied that you'd get "POST /BAR". However, little to no clients implemented it this way, and commonly changed the method to GET. This is somewhat understandable as the new, redirected resource is unknown to the user, and one shouldn't POST willy nilly to an unknown resource.
HTTP/1.1 clears this up - 302's should let the user know about the redirection. 307's make the redirection work as you would expect, maintaining the method.
AFNetworking is setup to act like all the other naughty clients out there - 302's alter the method to GET, giving the client a chance to alert the user. I just had this issue with AFNetworking myself: I set up some breakpoints, stepped through, and watched the method change before my eyes.
I haven't yet tested that 307's worked as defined with AFNetworking, but regardless, 302's are behaving in the odd way that HTTP/1.1 defined them to work.
tl;dr - In HTTP/1.1 use 307's to redirect and maintain the method, not 302's.
I ran into a similar issue where every POST request was being interpreted as a GET request. It turns out, similar to servers messing up when you're missing the trailing slash, the request type can get lost when your DNS redirects www.site.com to site.com or vice versa.
In my case, my DNS forces site.com to redirect to www.site.com, but I had set my base URLs to point to site.com. Thus, when I sent a request to my API at site.com/api, the request was redirected to www.site.com/api and the request type was lost, and the server defaulted to a GET request. So I added the www to my base URL, sent my request directly to www.site.com/api (avoiding the DNS redirect), and my POST requests started working again.
TL;DR: By adding the www (or removing it, depending on your DNS) I eliminated the redirect and fixed the problem.
I facing same problem, I using Laravel for server.
If my request is "http://localhost/api/abc/" then POST method send from client will became GET method in Server.
But if my request is "http://localhost/api/abc" (without "/"), then server will receive POST method.
I founded root cause is because of Redirect rule in .htaccess file:
In my .htaccess have these lines:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
These lines will change POST method to GET method if request have "/" in the end.
To fix this issue, I just comment out these lines.
Hope this help.
Another case you will encounter this issue is that when you set up redirection from HTTP to HTTPS automatically, the POST request will be redirected as GET request if this redirection setup is at work. Just updating your API endpoint to HTTPS resolves this case.

FineUploader - Hangs on uploading in FireFox over 350kb

Ok a problem has arisen today with FineUploader, it was working ok yesterday, and nothing has changed for the file upload part of the code.
The site is running on Windows Server 2008 R2, with IIS7 and all the service packs, and is running in MVC .Net 4.5.
The web.config has the required settings:
httpRuntime targetFramework="4.5" maxRequestLength="2147483647"
and
requestLimits maxAllowedContentLength="2147483647"
to allow large uploads, and it works on a local machine in Visual Studio no problem.
I can also run it on a local machines IIS and it works perfect also. The only problem is when its run from the actual live website. Unfortunately I cannot give out the live site.
When it fails in FF I get 'XHR returned response code 0'
The code for the uploader (excluding the on error/complete etc.. events) is:
manualuploader = $('#uploader').fineUploader({
request: {
endpoint: '/File/UploadFile',
} });
So I do not limit anything of type/size etc... in the code.
As I say it will work 100% of the time for files under about 350kb, anything over and it always freezes at around the 350-400kb mark (based on the percentage it stops at). After a few minutes it goes to the error call of fineuploader with the XHR 0 code.
It works every time ok in Chrome, works sometimes in IE but sometimes freezing at about 1.5MB and gives same error code, and freezes 100% of the time in FF with that error.
Oh and I don't think its a timeout as it takes about 1 or 2 seconds to get the the 400kb even on a slow connection, and then just hangs before crashing. Any ideas?
Request Header:
Accept text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cache-Control no-cache
Connection keep-alive
Content-Length 1861415
Content-Type multipart/form-data; boundary=---------------------------170602977010532
Cookie __RequestVerificationToken=zL6gveyPJ9FY-KvAQq9xHAdrdKTlezzuzwTXfMLETYbXCgFS9XJKRonvJ7vebBK1f9YCueXq8td33cX_10Xx_hfseiaszXq76PGgCKmHE0M1
Host REMOVED
Pragma no-cache
Referer REMOVED
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0
X-Requested-With XMLHttpRequest
[FineUploader] Error when attempting to parse xhr response text (SyntaxError: JSON.parse: unexpected end of data)
Then the POST part is this (excluding the garbage at the end which is presumably just the file data):
-----------------------------170602977010532 Content-Disposition: form-data; name="path" null -----------------------------170602977010532 Content-Disposition: form-data; name="qqpartindex" 0 -----------------------------170602977010532 Content-Disposition: form-data; name="qqpartbyteoffset" 0 -----------------------------170602977010532 Content-Disposition: form-data; name="qqchunksize" 1860320 -----------------------------170602977010532 Content-Disposition: form-data; name="qqtotalparts" 1 -----------------------------170602977010532 Content-Disposition: form-data; name="qqtotalfilesize" 1860320 -----------------------------170602977010532 Content-Disposition: form-data; name="qqfilename" 2013-04-21 19.05.30.jpg -----------------------------170602977010532 Content-Disposition: form-data; name="qquuid" e2732d70-3247-4555-bcbd-399aaa471d58 -----------------------------170602977010532 Content-Disposition: form-data; name="qqfile"; filename="blob" Content-Type: application/octet-stream
Seems pretty clear that this is a server-side issue. Also, you've stated that it worked fine yesterday, so something must have changed in your server-environment. According to the log message, something is likely interfering with the request. You'll need to spend some time looking at your server logs and code and examining any devices between your endpoint and your browser to figure out what is going wrong. Either your endpoint is not properly handling the request or something is interfering with the request before it hits your endpoint code. There's not much help I can offer as I don't know anything about your server environment. You'll need to do some troubleshooting.

Telerik MVC Extensions: Grid: During Ajax binding calls why is so much data posting back in the query string?

I am using Ajax binding with the Grid and ran into a problem where ASP.NET MVC was throwing a HttpRequestValidationException when I attempted an operation on the grid that invoked the Ajax call (like sorting).
Using Fiddler I was able to determine my browser was attempting to post back my entire model in the query string and there were some characters that would have triggered ASP.NET's request validation.
I was able to work around this by simply adding
[ValidateInput(false)]
to my controller action.
I'm wondering why was the grid sending back so much data? And is this a symptom of a bug in my code or Telerik's?
Here is what I saw in Fiddler (note the extremely long query string, even though the HTTP verb is "POST").
POST http://127.0.0.1:52601/MyController/DatabindGrid?Items=System.Collections.ObjectModel.Collection%601%5BPMyNamespace.Data.ViewEntities.Alert%5D&DetailsClientUrl=&GetJsonUrl=%2FMonitor%2FGetGridJson&ViewName=&CurrentItem=&PageTitle=My%20Web%20Page&CopyrightText=Copyright%20%26%23x00A9%3B%202004-2010%20My%20Company%20Corporation&BrowserCapabilities=&OemName=&UiVersion=20101123 HTTP/1.1
Referer: http://ipv4.fiddler:52601/MyController/MyAction
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: text/plain, */*; q=0.01
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host: 127.0.0.1:52601
Content-Length: 56
Connection: Keep-Alive
Pragma: no-cache
Cookie: ASP.NET_SessionId=bvgwuno4bounqio2werepkw4; .ASPXAUTH=612E18BB916F720D13A0F0D1695A86079B94DFE94A3BF5A9A8F19E35A37AE987282B7B684201C112CEC6081181E3D1C52C5517A66D9158E4CF83C1C3F523EE32FF783BD2E3B6E0A42A35E1874E63BA76C7735F9E8ABBA4E58BF61EB29DA03789E07A201A1BA9E7B85F941516ED7EA26E3E8E1E65D0836F39A109201E357EE97478D1A359B3FB4B4AD4C64A02A0CE7BBB39DC8FE1F73B179F284A14CF55D9C67D
page=1&size=10&orderBy=LocationName-asc&groupBy=&filter=
Rick,
I think you might be interested in this...
http://tv.telerik.com/watch/aspnet-mvc/video/building-a-responsive-site-with-mvc
very detailed and informative.
~AZee

Resources