Bug 4151 - USPS.com Label Printing Malfunction
Summary: USPS.com Label Printing Malfunction
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Frames (show other bugs)
Version: 420+
Hardware: Mac OS X 10.4
: P2 Normal
Assignee: Nobody
URL: https://sss-web.usps.com/
Keywords: InRadar, NeedsReduction
: 9530 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-07-26 21:59 PDT by Mathew Burrack
Modified: 2009-09-21 11:01 PDT (History)
7 users (show)

See Also:


Attachments
Sample PDF from USPS (32.55 KB, text/pdf)
2009-09-12 21:10 PDT, mitz
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 PDT, mitz
andersca: review-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mathew Burrack 2005-07-26 21:59:17 PDT
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 Chris Petersen 2005-07-28 23:00:25 PDT
Confiming this problem with TOT WebKit and Safari 2.0 (412.2).
Comment 2 Chris Petersen 2005-07-28 23:01:33 PDT
Apple radar bug : 4137135
Comment 3 Alexey Proskuryakov 2006-06-21 09:07:53 PDT
*** Bug 9530 has been marked as a duplicate of this bug. ***
Comment 4 mitz 2006-08-16 08:04:48 PDT
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 Alexey Proskuryakov 2006-08-16 13:43:36 PDT
I can still reproduce this, starting from <https://sss-web.usps.com>.
Comment 6 Ilgaz Öcal 2007-04-25 03:49:44 PDT
(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 David Kilzer (:ddkilzer) 2007-06-14 11:04:39 PDT
(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 David Kilzer (:ddkilzer) 2007-06-14 11:30:31 PDT
* 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 David Kilzer (:ddkilzer) 2007-06-14 23:17:02 PDT
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 David Kilzer (:ddkilzer) 2007-06-15 11:27:26 PDT
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 David Kilzer (:ddkilzer) 2007-06-15 16:46:28 PDT
* 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 David Kilzer (:ddkilzer) 2007-06-15 23:10:41 PDT
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 mitz 2009-09-12 21:10:15 PDT
Created attachment 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 mitz 2009-09-19 17:50:04 PDT
Created attachment 39827 [details]
Executes document-level JavaScript actions in PDFs, providing a Doc object with a print method
Comment 15 Anders Carlsson 2009-09-21 10:35:22 PDT
Comment on attachment 39827 [details]
Executes document-level JavaScript actions in PDFs, providing a Doc object with a print method

> +#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 mitz 2009-09-21 10:43:12 PDT
(In reply to comment #15)
> (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"?

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 mitz 2009-09-21 11:01:46 PDT
Updated version of the patch checked in as <http://trac.webkit.org/projects/webkit/changeset/48586>.