i'm new to go, and i'm trying to do a redirect after login.
for the router, i'm using Mux:
router.HandleFunc("/login", pages.Login).Methods("POST")
and the Login func contains these lines:
if errorFlag {
http.Redirect(rw, rq, "/", http.StatusNotAcceptable)
} else {
http.Redirect(rw, rq, "/", http.StatusOK)
}
thing is, i'm getting the correct status according to the errorFlag, but the page is not redirected! the headers also seem to be set correctly ("Location:/")
but instead of redirecting, the page just stays blank and remains under "/login"
i've tested it on Chrome & FF.
these are the response headers:
Content-Length:0
Content-Type:text/plain; charset=utf-8
Date:Thu, 14 Jan 2016 16:52:34 GMT
Location:localhost:8000/
Set-Cookie:user=MTQ1Mjc5MDM1N...; Path=/; Expires=Sat, 13 Feb 2016 16:52:34 UTC; Max-Age=2592000
anyone every encountered this before?
Update
As suggested below, this change works:
if errorFlag {
http.Redirect(rw, rq, "/", http.StatusTemporaryRedirect)
} else {
http.Redirect(rw, rq, "/", http.StatusFound)
}
thanks!
Use a 3xx status code to redirect the client (http.StatusFound, http.StatusMovedPermanently, http.StatusSeeOther, ...). The Location header is not sufficient to cause a redirect.
You are trying to redirect POST method so neither 301 (StatusMovedPermanently) nor 302 (StatusFound) should work according to W3.org.
Try returning 303 (StatusSeeOther) if you want to redirect with GET method. Try returning status 307 (StatusTemporaryRedirect) if you want to redirect with the same method as in the request.
Details here: https://softwareengineering.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect
Related
I'm building a simple server program that needs to return both an image and some text in the response, however, I'm having an issue with Jetty. The text should be included in headers of the HTTP response, but isn't.
Here's the code to return the image:
override fun doPost(request: HttpServletRequest, response: HttpServletResponse) {
response.contentType = "image/png"
response.status = HttpServletResponse.SC_OK
val diff = ImgDiff.getDifference("img1", "img2", tolerance)
//response.writer.println(diff.toString())
ImageIO.write(ImageIO.read(File("diffedFile.png")), "PNG", response.outputStream)
response.addHeader("diff", diff.toString())
}
This works fine, however, the header doesn't contain diff. When I use comment out the ImageIO line and uncomment the one above it, the already commented out one, and change the content type to text/plain diff is included in the headers.
The headers with the image:
Date: Mon, 13 May 2019 22:03:35 GMT
Content-Type: image/png
Transfer-Encoding: chunked
Server: Jetty(9.4.18.v20190429)
The headers without the image (As described in the latter case)
Date: Mon, 13 May 2019 22:10:32 GMT
Content-Type: text/plain;charset=iso-8859-1
diff: 62.62626262626263
Content-Length: 19
Server: Jetty(9.4.18.v20190429)
Am I doing something wrong with Jetty? Can HTTP response images not contain images? I realize I could just return a zip file containing the image and text but I think that's a bit much. Am I ignoring something fundamental to HTTP requests? Please let me know.
It seems to work if I add the headers before I print the image into the stream.
override fun doPost(request: HttpServletRequest, response: HttpServletResponse) {
response.contentType = "image/png"
response.status = HttpServletResponse.SC_OK
val diff = ImgDiff.getDifference("img1", "img2", tolerance)
response.addHeader("diff", diff.toString())
ImageIO.write(ImageIO.read(File("diffedFile.png")), "PNG", response.outputStream)
}
I have an app to create server certificate requests, just as if one were using java keytool or something. I'm trying to return the created certificate request and the key in a zip file, but for the life of me, I can't get my REST controller to respond to the http request. CORRECTION: The controller responds, but the code within the method is never executed.
The server does receive the request, because my CORS filter is executed. But I have a debug set in the controller method, and it's never triggered. Is the signature of the method correct? I need another set of eyes, please?
Here is my controller code:
#RequestMapping(method = RequestMethod.POST, value = "/generateCert/")
public ResponseEntity<InputStreamResource> generateCert(#RequestBody CertInfo certInfo) {
System.out.println("Received request to generate CSR...");
byte[] responseBytes = commonDataService.generateCsr(certInfo);
InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(responseBytes));
System.out.println("Generated CSR with length of " + responseBytes.length);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=certificate.zip")
.contentType(MediaType.parseMediaType("application/zip"))
.contentLength(responseBytes.length)
.body(resource);
}
And here is the Angular request:
generateCertificate(reqBody: GenerateCert) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
this.http.post(this.urlGenerateCert, JSON.stringify(reqBody), {headers: headers}).subscribe(
(data) => {
let dataType = data.type;
let binaryData = [];
binaryData.push(data);
this.certBlob = new Blob(binaryData);
});
return this.certBlob;
}
And finally, the request and response headers I copied from the Network Panel:
Response
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Authorization, Accept, X-Requested-With, remember-me
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3600
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Thu, 27 Dec 2018 22:48:00 GMT
Expires: 0
Location: http://localhost:8102/login
Pragma: no-cache
Set-Cookie: JSESSIONID=EDACE17328628D579670AD0FB53A6F35; Path=/; HttpOnly
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Request
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 205
Content-Type: application/json
Host: localhost:8102
Origin: http://localhost:4200
Referer: http://localhost:4200/generateCerts
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36
I really struggled with getting CORS working, so maybe that's interfering with the request? I hate to post all that code unless absolutely necessary. Anybody got any ideas?
Listing of request/response headers lack information on URL, method and most important response status code.
Seeing Location: http://localhost:8102/login among response headers I can guess that it could be 401 Unauthorized or anything else that redirects to the login page. Hence, if there is an auth filter in the filter chain, it may be a culprit.
The following request headers
Host: localhost:8102
Origin: http://localhost:4200
suggests that you are doing CORS and the CORS filter may be involved indeed and fulfill response before the request gets routed to the controller. I suggest setting a breakpoint into the CORS filter (and into others if any) and debug it to the point where the response is returned.
define a proxy.conf.json
{
"/login*": {
"target":"http://localhost:8080",
"secure":false,
"logLevel":"debug"
}
}
now in your package.json
"scripts": {
"start":"ng serve --proxy-config proxy.config.json"
}
I think there is issue while getting connection in both webapp.please try .
When Angular encounters this statement
this.http.post(url,body).subscribe(data => # some code
);
It comes back immediately to run rest of the code while service continues to execute. Just like Future in Java.
Here if you
return this.cert;
You will not get the value that may eventually get populated by the this.http service. Since the page has already rendered and the code executed. You can verify this by including this within and outside the Observable.
console.log(“Inside/outside observable” + new Date().toLocalTimeString());
Thanks to everyone who contributed. I discovered the error was due to the headers of my controller method. After changing them, the method was invoked properly. This is what worked:
#RequestMapping(method = RequestMethod.POST, path = "/generateCert",
produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<byte[]> generateCert(#RequestBody CertInfo certInfo) {
byte[] responseBytes = commonDataService.generateCsr(certInfo);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
.contentLength(responseBytes.length)
.body(responseBytes);
}
In the apache virtualHost i have these commands:
ProxyPass "/s" "http://127.0.0.1:3001"
ProxyPassReverse "/s" "http://127.0.0.1:3001"
RewriteRule ^/s/(.*) http://127.0.0.1:3001/$1 [P,L]
ProxyPassReverseCookiePath "/" "/"
The backend server is NodeJS. The proxy itself works fine. The problem is that the Node is sending a set-cookie in the HTTP header (session ID) but the browser seems to ignore it. I tested with Chromium and Firefox but none creates the cookie. I tried to change the virtualhost configuration but nothing appears to solve the problem The set-cookie command is:
set-cookie: sid=s%3AhgHWDO3D...BBUZbbOA; Path=/; HttpOnly; Secure;HttpOnly;Secure
I need your help to solve this problem. Thank you.
UPDATE
If the url is containing a direct request for the Node:
https://example.com/s/backend
it works. It creates the session is cookie. But if this URL is called from a AJAX request in the JS, it does not create the cookie.
The https://example.com load a HTML with a script load of a JS file. That JS file makes the AJAX call to the backend using the path https://example.com/s/something and in this case the cookie is never created.
Any suggestions?
UPDATE
I discovered that the problem is when i use the Fetch API to retrieve a JSON file. This code running does not create the session ID cookie:
fetch("https://localbestbatteriesonline.com/s/p.json?0103")
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
But if i have this code, it creates the cookie:
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
};
xhttp.open("GET", "https://localbestbatteriesonline.com/s/p.json?0103", true);
xhttp.send();
Analysing the requests, both are exactly the same. Both receive the cookie to create.
Any ideas why with the fetch does not work?
Problem solved. Using the Fetch API does not include the cookies exchange like it does in the XMLHttpRequest. Therefor, it does not create the session id cookie. To enable this, the Fetch call must have the option:
credentials:"same-origin".
fetch("https://localbestbatteriesonline.com/s/p.json?0103",{credentials:"same-origin"})
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
Now it works.
Something very odd is happening with my ASP.NET application where I've created a login portal, and whenever the login is complete about 75% of the time I get redirected to favicon.ico.
For example, here is the login page that I sign in to:
Then after I enter my e-mail and password, I somehow end up here:
The ReturnUrl is being used as a redirect after login, and %2f being the forward slash, it should take the user to the default. Instead it somehow ends up at favicon.ico.
I really don't understand this, especially since it does not happen all of the time. I do see the behavior across Firefox, Chrome, and IE11. In the cases where it does not happen, I land on https://172.16.0.20, the default.
Here is how I route in the controller:
[HttpPost]
public ActionResult Login(Models.LoginViewModel login)
{
User u = null;
if (ModelState.IsValid)
{
if (authProvider.Authenticate(login.Email, login.Password, login.RememberMe, out u))
{
return Redirect((TempData["ReturnUrl"] == null) ? Url.Action("Index", "Home") : (string)TempData["ReturnUrl"]);
}
else
{
ModelState.AddModelError("", "Incorrect username or password");
return View();
}
}
else
{
return View();
}
}
Here is my only route:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
EDIT: From using Fiddler, as suggested, it looks like at some point it tries to get favicon.ico and the server responds with its location, changing the ReturnUrl:
GET http://172.16.0.20/favicon.ico HTTP/1.1
Host: 172.16.0.20
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: ASP.NET_SessionId=gp1osbxvm5uawvfmsu3is5db
Connection: keep-alive
HTTP/1.1 302 Found
Location: /Account/Login?ReturnUrl=%2ffavicon.ico
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Date: Mon, 15 Dec 2014 15:51:29 GMT
Content-Length: 156
What is the proper way to handle this?
The reason favicon.ico is called is because that is the standard thumbnail image url. Browsers use the image data to populate the little website logo in the left of your chrome tabs (other browsers may put the logo elsewhere).
Additionally, if you don't specify a mobile-optimized logo, when you save a web page to your home screen in iOS (and probably android too), they will use the favicon.ico as the icon. Additionally, different browsers have different rules for how often they refresh the file so you can't really predict when it will get requested, and all the major browsers check it.
You should solve this problem generally. That is, if your code sticks the last requested URL into the TempData["ReturnUrl"], you will also have issues if a user happens to request any images as well from a tag like
<img src="/someOtherReturnUrl.jpg" />
So one solution is to change the place where you populate TempData["ReturnUrl"] to only store if it's a Controller that is serving a page as opposed to a static file. There are ways to check this in an HttpModule or in an ActionFilter which is probably what you're using.
Alternatively, and this is probably simpler to do, change your code to be:
if (authProvider.Authenticate(login.Email, login.Password, login.RememberMe, out u))
{
return Redirect((!string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
? Request.QueryString["ReturnUrl"]
: Url.Action("Index", "Home");
}
Because it looks like your login page is of the url pattern: /account/login?ReturnUrl=SomeUrl and the query string is more consistent than whatever the previous request happened to be. Seriously, on the web you cannot guarantee request order, ever. (or at least it's usually a bad idea to assume a rational order because users and browsers do all sorts of wacky and inventive things).
I am doing this:
domain.com/route-name/?do-something=1
..which sets a cookie and then redirects to this using a 302 redirect:
domain.com/route-name/
It allows an action to take place regardless of the page viewing (cookie stores a setting for the user).
I am using the default Symfony2 reverse-proxy cache and all is well, but I need to prevent both the above requests from caching.
I am using this to perform the redirect:
// $event being a listener, usually a request listener
$response = new RedirectResponse($url, 302);
$this->event->setResponse($response);
I've tried things like this but nothing seems to work:
$response->setCache(array('max_age' => 0));
header("Cache-Control: no-cache");
So how do I stop it caching those pages?
You have to make sure you are sending the following headers with the RedirectResponse ( if the GET parameter is set ) AND with your regular Response for the route:
Cache-Control: private, max-age=0, must-revalidate, no-store;
Achieve what you want like this:
$response->setPrivate();
$response->setMaxAge(0);
$response->setSharedMaxAge(0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);
private is important and missing in coma's answer.
The difference is that with Cache-Control: private you are not allowing proxies to cache the data that travels through them.
Try this on your response:
$response->headers->addCacheControlDirective('no-cache', true);
$response->headers->addCacheControlDirective('max-age', 0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);
You can use annotations too:
http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/cache.html
And take a look at:
Why both no-cache and no-store should be used in HTTP response?