benlucchesi / grails-cookie-session

cookie sessions for grails applications
28 stars 32 forks source link

man, how do I describe this. sending existing cookie with new internal URL request for pdf request #67

Closed tmcgrath closed 8 years ago

tmcgrath commented 8 years ago

Happy user of this plugin, but ran into an edge case today.

When generating PDFs from our site, we make a connection using URL and then write the HTML file to file system. Then we use this file system file to convert to PDF.

More or less, the following code from Grails controller shows what I'm trying to describe:

  URL print = new URL(printurl);
  HttpURLConnection con = (HttpURLConnection)print.openConnection();
  String xhtmlFileString = "${getConfig(CSSPATH)}${request.getSession().getId().substring(0, 10)}-gp.html"
  File xhtmlFile = new File(xhtmlFileString);
  FileOutputStream fos = new FileOutputStream(xhtmlFile)

Then we run a command line tool to convert the file to PDF.

The part related to grails-cookie-session is in printurl variable above. Previous to the plugin, we tacked on jsessionid= and the session id of the current user on to printurl to make the URLConnection and still utilize values stored in the session. Hopefully, you see what I'm trying to describe.

With grails-cookie-session, we can't do that anymore.

Any ideas on how to resolve?

Best I have so far is adding the existing cookie to the con request like

con.setRequestProperty("Cookie", "name1=value1; name2=value2");

where Cookie is the name of the cookie configured cookiename such as "gsession"

Ideas? Suggestions?

benlucchesi commented 8 years ago

Hey Todd,

Why not just put their print queue id in their session? It will be stored as a cookie anyways via cookie sessions, so there's no need to create your own cookie to store it.

// somewhere early in the process... session.printQueueID = []

// at the time they submit a job def fileID = java.util.UUID.randomUUID() def xhtmlFileString = "${getConfig(CSSPATH)}${printID}-gp.html" // you can store the ID's or the entire URI where to retrieve the file... session.printQueue << xhtmlFileString // or session.printQueue << fileID

// later on session.printQueueID.removeElement(....)

hope this helps!

On Thu, Jun 16, 2016 at 12:25 PM, Todd McGrath notifications@github.com wrote:

Happy user of this plugin, but ran into an edge case today.

When generating PDFs from our site, we make a connection using URL and then write the HTML file to file system. Then we use this file system file to convert to PDF.

More or less, the following code from Grails controller shows what I'm trying to describe:

URL print = new URL(printurl); HttpURLConnection con = (HttpURLConnection)print.openConnection(); String xhtmlFileString = "${getConfig(CSSPATH)}${request.getSession().getId().substring(0, 10)}-gp.html" File xhtmlFile = new File(xhtmlFileString); FileOutputStream fos = new FileOutputStream(xhtmlFile)

Then we run a command line tool to convert the file to PDF.

The part related to grails-cookie-session is in printurl variable above. Previous to the plugin, we tacked on jsessionid= and the session id of the current user on to printurl to make the URLConnection and still utilize values stored in the session. Hopefully, you see what I'm trying to describe.

With grails-cookie-session, we can't do that anymore.

Any ideas on how to resolve?

Best I have so far is adding the existing cookie to the con request like

con.setRequestProperty("Cookie", "name1=value1; name2=value2");

where Cookie is the name of the cookie configured cookiename such as "gsession"

Ideas? Suggestions?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/benlucchesi/grails-cookie-session/issues/67, or mute the thread https://github.com/notifications/unsubscribe/AAwojBU0H_aT-6vwa7Pejs_3XwodJz5Oks5qMaM-gaJpZM4I3uMq .

tmcgrath commented 8 years ago

Thanks for fast response!

I don't think that will work. This code assumes the file has already been generated and updates session with xhtmlFileString or the fileID. But this assumes the file has already been generated which is the problem I believe. But you didn't have enough information. My bad. Here's more

The user accesses the site through some public URL such as www.test.com. Then when they want to generate a PDF and access code posted above, the printurl will be something like http://localhost:8080/generatePDF?jsessionid=xcvzzv&pages=page1,page2,page3

When this worked before, the request relied on passing around jsessionid for session association between requests. But, now this request doesn't work with jsessionid and also because (I believe) the request isn't sending the cookies with the request.

Thoughts?

benlucchesi commented 8 years ago

well... jsession id is a unique to every session and a user only has one of them. so I'm guessing that you're only able to run one generatePDF at a time, especially if you're putting the ID in the file name.

Is the URL where you access the site and the URL where you run generatePPF on the same domain. I'm assuming it is, otherwise, you wouldn't have access to their jsession id stored in a cookie to then put on the URL. If this is the case, then you can share the cookie session between both application. OR are you actually send the user to a locahost:8080/generatePDF on their machine?

On Thu, Jun 16, 2016 at 12:54 PM, Todd McGrath notifications@github.com wrote:

Thanks for fast response!

I don't think that will work. This code assumes the file has already been generated and updates session with xhtmlFileString or the fileID. But this assumes the file has already been generated which is the problem I believe. But you didn't have enough information. My bad. Here's more

The user accesses the site through some public URL such as www.test.com. Then when they want to generate a PDF and access code posted above, the printurl will be something like http://localhost:8080/generatePDF?jsessionid=xcvzzv&pages=page1,page2,page3

When this worked before, the request relied on passing around jsessionid for session association between requests. But, now this request doesn't work with jsessionid and also because (I believe) the request isn't sending the cookies with the request.

Thoughts?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/benlucchesi/grails-cookie-session/issues/67#issuecomment-226595007, or mute the thread https://github.com/notifications/unsubscribe/AAwojL-jP3hTWkY0X-2xdFsH3bCcr3veks5qManogaJpZM4I3uMq .

tmcgrath commented 8 years ago

Yes, same machine. But, the problem appears to be when making this call

URL print = new URL(printurl); HttpURLConnection con = (HttpURLConnection)print.openConnection();

The server doesn't think it's the same session. Before, when we didn't use cookie-session plugin, it worked.

benlucchesi commented 8 years ago

Is the public server calling a private URL /generatePDF as a form of RPC or is the client's browser calling the URL /generatePDF?

On Thu, Jun 16, 2016 at 1:41 PM, Todd McGrath notifications@github.com wrote:

Yes, same machine. But, the problem appears to be when making this call

URL print = new URL(printurl); HttpURLConnection con = (HttpURLConnection)print.openConnection();

The server doesn't think it's the same session. Before, when we didn't use cookie-session plugin, it worked.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/benlucchesi/grails-cookie-session/issues/67#issuecomment-226607423, or mute the thread https://github.com/notifications/unsubscribe/AAwojIM2nmw16E_h1Gaydlggxw_oViVvks5qMbT4gaJpZM4I3uMq .

tmcgrath commented 8 years ago

public server calling a private URL /generatePDF. It's calling itself in order to generate the static file used as source for PDF conversion:

File xhtmlFile = new File(xhtmlFileString);
FileOutputStream fos = new FileOutputStream(xhtmlFile)

Tidy tidy = new Tidy();
tidy.setXHTML(true);
tidy.parse(con.getInputStream(), fos);
fos.close();

Then, we use wkhtmltopdf to generate the PDF similar to the following

  wkhtmltopdf --enable-plugins --page-size Letter --load-error-handling ignore ${xhtmlFileString} /tmp/${sessionID}_print.pdf"
benlucchesi commented 8 years ago

ok, I understand... basically your app is calling itself as a cheap way of implementing asynchronous calls???

so the issue is that your application is opening a session with itself... client browser calls the server, server creates a session and stuffs it in cookie which get sent back to browser... on one of the calls to the server, the server calls itself on a URL which creates a session completely separate session...

The reason your jsession id solution worked is because spring accepts jsession id's on the query string as a fallback to a jsession cookie. because this was all happening on the same server, the internal call to the /generatePDF was able to access the in-memory session using the jsession id. Because the cookie session is shared between the browser and the first call to the server ONLY and because the server gets a new session when it calls itself, the internal call doesn't have the client's session data.

Does the call to generatePDF need access to more information in the session (authentication, etc) or just the print queue ID? If it just needs the print queue id, then I'd still just stuff a value in the session before calling /generatePDF?id=(id in session). Alternatively, you could implement async handling using reactor pretty easily and then just do everything in a single application.

On Thu, Jun 16, 2016 at 1:49 PM, Todd McGrath notifications@github.com wrote:

public server calling a private URL /generatePDF. It's calling itself actually in order to generate the static file used as source for PDF conversion:

File xhtmlFile = new File(xhtmlFileString); FileOutputStream fos = new FileOutputStream(xhtmlFile) FileOutputStream fos = new FileOutputStream(xhtmlFile)

Tidy tidy = new Tidy(); tidy.setXHTML(true); tidy.parse(con.getInputStream(), fos); fos.close();

Then, we use wkhtmltopdf to generate the PDF similar to the following

wkhtmltopdf --enable-plugins --page-size Letter --load-error-handling ignore ${xhtmlFileString} /tmp/${sessionID}_print.pdf"

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/benlucchesi/grails-cookie-session/issues/67#issuecomment-226609600, or mute the thread https://github.com/notifications/unsubscribe/AAwojA8bKjbkF4eNUpuY45OQySMV9F3vks5qMbblgaJpZM4I3uMq .

tmcgrath commented 8 years ago

Thanks for staying with me. Yes, the call to generatePDF need access to more information in the session (authentication, etc). It needs values in the session in order to create the appropriate response to itself.

Example: the call to printurl may be producing a page with value specific to the logged in user; i.e.

Hello ${first_name}

Cheap example, but you get the idea.

So, I was thinking one way to potentially solve this was to take the cookie from the original request and then add it the second request to itself. But, that's all I got.

I was wondering if that would even work or if there is a better alternative.

Thoughts?

benlucchesi commented 8 years ago

I was thinking the same thing - stuffing the cookie session into your request. However, I think that will be fraught with problems. Because you're using the generatePDF method like a REST service, I would try to make it as stateless as possible and pass in virtually everything you need as serialized JSON as part of the query string. But if it was me and I really needed the user's session, then I'd rework it so that the call to generate the PDF so that it could be run asynchronously from the main call from the client as opposed to having the application call itself on a URL

On Thu, Jun 16, 2016 at 2:23 PM, Todd McGrath notifications@github.com wrote:

Thanks for staying with me. Yes, the call to generatePDF need access to more information in the session (authentication, etc). It needs values in the session in order to create the appropriate response to itself.

Example: the call to printurl may be producing a page with value specific to the logged in user; i.e.

Hello ${first_name}

Cheap example, but you get the idea.

So, I was thinking one way to potentially solve this was to take the cookie from the original request and then add it the second request to itself. But, that's all I got.

I was wondering if that would even work or if there is a better alternative.

Thoughts?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/benlucchesi/grails-cookie-session/issues/67#issuecomment-226618002, or mute the thread https://github.com/notifications/unsubscribe/AAwojF6aW_PSwiiX3HEl4YFDCGo9hApHks5qMb7BgaJpZM4I3uMq .

tmcgrath commented 8 years ago

Yes, it is like a REST call and that's the best idea by far. I'm going to update the generatePDF call to be stateless. Thank you for thinking this through with me! I'll close this one up