Bug 4151 - USPS.com Label Printing Malfunction
: USPS.com Label Printing Malfunction
Status: RESOLVED FIXED
: WebKit
Frames
: 420+
: Macintosh Mac OS X 10.4
: P2 Normal
Assigned To:
: https://sss-web.usps.com/
: InRadar, NeedsReduction, ReviewedForR...
:
:
  Show dependency treegraph
 
Reported: 2005-07-26 21:59 PST by
Modified: 2009-09-21 11:01 PST (History)


Attachments
Sample PDF from USPS (32.55 KB, text/pdf)
2009-09-12 21:10 PST, mitz@webkit.org
no flags Details
Executes document-level JavaScript actions in PDFs, providing a Doc object with a print method (22.77 KB, patch)
2009-09-19 17:50 PST, mitz@webkit.org
andersca: review-
Review Patch | Details | Formatted Diff | Diff


Note

You need to log in before you can comment on or make changes to this bug.


Description From 2005-07-26 21:59:17 PST
The USPS website includes functionality for purchasing and printing a shipping label. They recently 
updated the method by which they generate and print the label, and while the old method worked on 
Safari, the new one does not. The culprit appears to be that the page loaded includes an <iframe> tag of 
width and height 0 which contains the PDF file of the label to print, but the PDF file is never sent to the 
printer as the page indicates should happen. Instead, the page simply sits idle after loading. If I go into 
the "Activity" window, I can see the PDF listed and I can double-click it to open the PDF in a separate 
window and print it properly, so this problem can be worked around, even if the workaround is not 
obvious. This bug is 100% reproducable.
------- Comment #1 From 2005-07-28 23:00:25 PST -------
Confiming this problem with TOT WebKit and Safari 2.0 (412.2).
------- Comment #2 From 2005-07-28 23:01:33 PST -------
Apple radar bug : 4137135
------- Comment #3 From 2006-06-21 09:07:53 PST -------
*** Bug 9530 has been marked as a duplicate of this bug. ***
------- Comment #4 From 2006-08-16 08:04:48 PST -------
Since this bug was reported, there have been changes to the way hidden frames are loaded (namely, now they are loaded). The original URL for this bug doesn't work anymore. Could the reporter please check if the bug still exists in the latest nightly builds?
------- Comment #5 From 2006-08-16 13:43:36 PST -------
I can still reproduce this, starting from <https://sss-web.usps.com>.
------- Comment #6 From 2007-04-25 03:49:44 PST -------
(In reply to comment #4)
> Since this bug was reported, there have been changes to the way hidden frames
> are loaded (namely, now they are loaded). The original URL for this bug doesn't
> work anymore. Could the reporter please check if the bug still exists in the
> latest nightly builds?
> 

I tested with current nightly via clicking "sample international label" and "Sample domestic label", both opened Adobe Acrobat Reader 8 as result showing the label correctly.
------- Comment #7 From 2007-06-14 11:04:39 PST -------
(In reply to comment #6)
> I tested with current nightly via clicking "sample international label" and
> "Sample domestic label", both opened Adobe Acrobat Reader 8 as result showing
> the label correctly.

Did you log in to click the sample link?  I am still able to reproduce this using a local debug build of WebKit r23502 with Safari 3.0 (522.11) on Mac OS X 10.4.9 (8P135).
------- Comment #8 From 2007-06-14 11:30:31 PST -------
* STEPS TO REPRODUCE
1. Launch Safari/WebKit.
2. Go to URL: https://sss-web.usps.com
3. Click "Sign In" button.
4. Enter username/password, then click "Sign In" button.
5. Fill out information, the click "Continue" button to create a new label.
NOTE: If you fill out an email address, a message will likely be sent to that address while testing!
6. Select a mail service (Priority, Express, etc.), then select the "Print label without postage" radio button, then click "Continue".
7. Click "Continue" button to select the new label created.
8. Click the "Print Sample Label" link.
9. Wait for the new page to completely load.

* EXPECTED RESULTS
A PDF containing the label should open in Preview or open in a new browser window.

* ACTUAL RESULTS
No PDF opens or is otherwise displayed.

* NOTES
I'm not sure how the PDF is being sent since SSL is in use, but I suspect a multipart "server push" is being used with a MIME type of multipart/x-mixed-replace.
------- Comment #9 From 2007-06-14 23:17:02 PST -------
What happens is that the results page loads the PDF into an <iframe> element that has width=0 and height=0.  On Firefox 2.0.0.4, the PDF is opened in an external viewer, which works great.  In Safari, the PDF is displayed inline in the 0x0 iframe, so the user never sees it!

I don't think this may be fixed by changing WebKit.  We may need to contact the USPS to fix their web site.
------- Comment #10 From 2007-06-15 11:27:26 PST -------
USPS FAQ for using Click-n-Ship(R) on Safari:

https://hdusps.esecurecare.net/cgi-bin/hdusps.cfg/php/enduser/prnt_adp.php?p_faqid=6467&p_sid=C5avpcEi
------- Comment #11 From 2007-06-15 16:46:28 PST -------
* WORKAROUND
If you cut and paste this JavaScript in the address bar on the page where the PDF is supposed to be displayed, it will open the PDF in another browser window that may then be printed.

javascript:var u = document.getElementById("iframeTable").childNodes[1].childNodes[0].childNodes[1].childNodes[1].src; window.open(u, '_blank');

You may also save it as a text clipping (make sure it is on one line!), then drag the text clipping into the address bar to run the JavaScript.
------- Comment #12 From 2007-06-15 23:10:41 PST -------
Another work-around would be to force Safari to save PDFs to the default download folder instead of viewing them inline by running this command:

$ defaults write com.apple.Safari WebKitOmitPDFSupport -bool YES
------- Comment #13 From 2009-09-12 21:10:15 PST -------
Created an attachment (id=39525) [details]
Sample PDF from USPS

Looking at the PDF served to WebKit (attached), I see these definitions:
48 0 obj<</S/JavaScript/JS(this.print\(true\);)>>
endobj
47 0 obj<</Count 1/Type/Pages/Kids[2 0 R]>>
endobj
49 0 obj<</Names[(0) 48 0 R]>>
endobj
50 0 obj<</JavaScript 49 0 R>>
endobj
51 0 obj<</Type/Catalog/ViewerPreferences<</HideMenubar true/HideToolbar true/HideWindowUI true>>/Pages 47 0 R/Names 50 0 R>>

While all I can tell is that it assigns the name “0” to the script “this.print(true)”, I suspect that this is what causes the document to print when opened in Adobe Reader 9 or the Adobe PDF plug-in. As far as I can tell, PDFKit does not interpret or expose JavaScript actions in the document.
------- Comment #14 From 2009-09-19 17:50:04 PST -------
Created an attachment (id=39827) [details]
Executes document-level JavaScript actions in PDFs, providing a Doc object with a print method
------- Comment #15 From 2009-09-21 10:35:22 PST -------
(From update of attachment 39827 [details])
> +#import <JavaScriptCore/JSBase.h>
> +
> +@class WebDataSource;
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +JSObjectRef makeJSPDFDoc(JSContextRef, WebDataSource *);
> +#ifdef __cplusplus
> +}
> +#endif

Why does this need to be extern "C"?

> +static void jsPDFDocInitialize(JSContextRef ctx, JSObjectRef object)
> +{
> +    WebDataSource *dataSource = (WebDataSource *)JSObjectGetPrivate(object);
> +    [dataSource retain];
> +}

This should use CFRetain or it'll break under GC

> +
> +static void jsPDFDocFinalize(JSObjectRef object)
> +{
> +    WebDataSource *dataSource = (WebDataSource *)JSObjectGetPrivate(object);
> +    [dataSource release];
> +}

Same here, use CFRelease.

> +
> +static JSValueRef jsPDFDocPrint(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
> +{
> +    WebDataSource *dataSource = (WebDataSource *)JSObjectGetPrivate(thisObject);
> +
> +    WebView *webView = [[dataSource webFrame] webView];
> +    CallUIDelegate(webView, @selector(webView:printFrameView:), [[dataSource webFrame] frameView]);

Is there no internal method for printing a frame view?

> +
> +    return JSValueMakeNull(ctx);

"void" javascript functions usually return undefined. Are you sure this should return null?

> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +void addWebPDFDocumentExtras(Class);
> +#ifdef __cplusplus
> +}
> +#endif

Again, why does this need to be extern C?

> +
> +void addWebPDFDocumentExtras(Class pdfDocumentClass)
> +{
> +#ifndef BUILDING_ON_TIGER
> +    class_addMethod(pdfDocumentClass, @selector(_web_allScripts), (IMP)web_PDFDocumentAllScripts, "@@:");
> +#else
> +    struct objc_method_list methodList = { 0, 1, { @selector(_web_allScripts), (IMP)web_PDFDocumentAllScripts, "@@:" } };
> +    class_addMethods(pdfDocumentClass, &methodList);
> +#endif

Why do you need to add this to the class? Can't you just use a category method?

> ++ (void)initialize
> +{
> +    Class pdfDocumentClass = [self PDFDocumentClass];
> +    if (pdfDocumentClass)
> +        addWebPDFDocumentExtras(pdfDocumentClass);

+initialize should check if self == [WebPDFRepresentation class] to guard against adding the same extras more than once.
------- Comment #16 From 2009-09-21 10:43:12 PST -------
(In reply to comment #15)
> (From update of attachment 39827 [details] [details])
> > +#import <JavaScriptCore/JSBase.h>
> > +
> > +@class WebDataSource;
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +JSObjectRef makeJSPDFDoc(JSContextRef, WebDataSource *);
> > +#ifdef __cplusplus
> > +}
> > +#endif
> 
> Why does this need to be extern "C"?

Because it is called from Objective-C (in WebPDFRepresentation.m).

> > +static void jsPDFDocInitialize(JSContextRef ctx, JSObjectRef object)
> > +{
> > +    WebDataSource *dataSource = (WebDataSource *)JSObjectGetPrivate(object);
> > +    [dataSource retain];
> > +}
> 
> This should use CFRetain or it'll break under GC

I will change it. Why isn’t it enough that the JavaScript object has the data source as its private object to protect it from Obj-C GC?

> > +
> > +static void jsPDFDocFinalize(JSObjectRef object)
> > +{
> > +    WebDataSource *dataSource = (WebDataSource *)JSObjectGetPrivate(object);
> > +    [dataSource release];
> > +}
> 
> Same here, use CFRelease.

Will change.

> 
> > +
> > +static JSValueRef jsPDFDocPrint(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
> > +{
> > +    WebDataSource *dataSource = (WebDataSource *)JSObjectGetPrivate(thisObject);
> > +
> > +    WebView *webView = [[dataSource webFrame] webView];
> > +    CallUIDelegate(webView, @selector(webView:printFrameView:), [[dataSource webFrame] frameView]);
> 
> Is there no internal method for printing a frame view?

I think there is. I am not sure why you are asking. This is analogous to how window.print is handled, and to what clicking the Print button in the PDF HUD does.

> > +    return JSValueMakeNull(ctx);
> 
> "void" javascript functions usually return undefined. Are you sure this should
> return null?

No. I will change it to return undefined.

> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +void addWebPDFDocumentExtras(Class);
> > +#ifdef __cplusplus
> > +}
> > +#endif
> 
> Again, why does this need to be extern C?

Because it is called from Objective-C (in WebPDFRepresentation.m).

> 
> > +
> > +void addWebPDFDocumentExtras(Class pdfDocumentClass)
> > +{
> > +#ifndef BUILDING_ON_TIGER
> > +    class_addMethod(pdfDocumentClass, @selector(_web_allScripts), (IMP)web_PDFDocumentAllScripts, "@@:");
> > +#else
> > +    struct objc_method_list methodList = { 0, 1, { @selector(_web_allScripts), (IMP)web_PDFDocumentAllScripts, "@@:" } };
> > +    class_addMethods(pdfDocumentClass, &methodList);
> > +#endif
> 
> Why do you need to add this to the class? Can't you just use a category method?

There is no way to add category methods dynamically at runtime. As far as I can tell, at least in the Objective-C 2.0 runtime, categories are not a runtime concept. For what it’s worth, I do declare the method as a category method.

> > ++ (void)initialize
> > +{
> > +    Class pdfDocumentClass = [self PDFDocumentClass];
> > +    if (pdfDocumentClass)
> > +        addWebPDFDocumentExtras(pdfDocumentClass);
> 
> +initialize should check if self == [WebPDFRepresentation class] to guard
> against adding the same extras more than once.

I will add the check.

Thanks for the review!
------- Comment #17 From 2009-09-21 11:01:46 PST -------
Updated version of the patch checked in as <http://trac.webkit.org/projects/webkit/changeset/48586>.