Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to print to CUPS URL #384

Open
paul-cureton opened this issue Nov 20, 2018 · 3 comments
Open

Ability to print to CUPS URL #384

paul-cureton opened this issue Nov 20, 2018 · 3 comments
Milestone

Comments

@paul-cureton
Copy link

I am attempting to print ZPL to a CUPS printer URL. The documentation shows:

function printToURL() {
   var config = qz.configs.create({ host: "192.168.254.254", port: 9100 }); // or http://<cups-server>/printers/<my-printer>
   //...
}

I have attempted a few different combinations for the qz.configs.create() function:

  • qz.configs.create('http://<cups-server>:<port>/printers/<my-printer>')
  • qz.configs.create({host: 'http://<cups-server>/printers/<my-printer>', port: <port>})
  • qz.configs.create({host: 'http://<cups-server>:<port>/printers/<my-printer>'})

Regardless of how I create the config, I get a java.net.UnknownHostException.

I can successfully print (same payload) with the alternatePrinting: true option as well as using a RAW socket instead of a CUPS URI. The CUPS server requires no authentication, and I have verified it works both locally and remotely. The CUPS queue is configured as a raw queue.

Here a log of an attempt, with my network IPs and queue names removed:

[DEBUG] 2018-11-20 10:59:28,054 @ qz.ws.PrintSocketClient:?
	Message: {"call":"print","promise":{},"params":{"printer":{"name":"http://<cups-server>:<port>/printers/<printer-name>"},"options":{"colorType":"color","copies":1,"density":0,"duplex":false,"fallbackDensity":null,"interpolation":"bicubic","jobName":null,"legacy":false,"margins":0,"orientation":null,"paperThickness":null,"printerTray":null,"rasterize":true,"rotation":0,"scaleContent":true,"size":null,"units":"in","altPrinting":false,"encoding":null,"endOfDoc":null,"perSpool":1},"data":["^XA\n","^FO50,100",{"type":"raw","format":"image","data":"https://demo.qz.io/assets/img/image_sample_bw.png","options":{"language":"ZPLII"}},"^FS\n","^FO50,300^ADN,36,20^FDPRINTED USING^FS\n","^FO50,350^ADN,36,20^FDQZ-TRAY ^FS\n","^FO50,400^ADN,36,20^FDVERSION 2.0.7^FS\n\n","^XZ\n"]},"timestamp":1542733168049,"uid":"aedjz5","position":{"x":960,"y":540}}
[WARN] 2018-11-20 10:59:28,056 @ qz.ws.PrintSocketClient:?
	Bad signature on request
[DEBUG] 2018-11-20 10:59:28,066 @ qz.common.TrayManager:?
	Calculated dialog centered at: java.awt.Point[x=649,y=467]
[INFO] 2018-11-20 10:59:29,854 @ qz.common.TrayManager:?
	Allowed localhost to print to http://<cups-server>:<port>/printers/<printer-name>
[TRACE] 2018-11-20 10:59:29,855 @ qz.utils.PrintingUtilities:?
	Waiting for processor, 0/1 already in use
[DEBUG] 2018-11-20 10:59:29,857 @ qz.utils.PrintingUtilities:?
	Using qz.printer.action.PrintRaw to print
[DEBUG] 2018-11-20 10:59:29,858 @ qz.printer.PrintServiceMatcher:?
	Searching for PrintService matching http://<cups-server>:<port>/printers/<printer-name>
[DEBUG] 2018-11-20 10:59:29,858 @ qz.printer.PrintServiceMatcher:?
	Found 3 printers
[WARN] 2018-11-20 10:59:29,859 @ qz.printer.PrintServiceMatcher:?
	Printer not found: http://<cups-server>:<port>/printers/<printer-name>
[ERROR] 2018-11-20 10:59:29,859 @ qz.utils.PrintingUtilities:?
	Failed to print
java.lang.IllegalArgumentException: Cannot find printer with name "http://<cups-server>:<port>/printers/<printer-name>"
	at qz.printer.PrintOutput.<init>(Unknown Source)
	at qz.utils.PrintingUtilities.processPrintRequest(Unknown Source)
	at qz.ws.PrintSocketClient.processMessage(Unknown Source)
	at qz.ws.PrintSocketClient.onMessage(Unknown Source)
	at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
	at java.lang.reflect.Method.invoke(Method.java:508)
	at org.eclipse.jetty.websocket.common.events.annotated.CallableMethod.call(CallableMethod.java:70)
	at org.eclipse.jetty.websocket.common.events.annotated.OptionalSessionCallableMethod.call(OptionalSessionCallableMethod.java:68)
	at org.eclipse.jetty.websocket.common.events.JettyAnnotatedEventDriver$2.run(JettyAnnotatedEventDriver.java:210)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
	at java.lang.Thread.run(Thread.java:812)
[TRACE] 2018-11-20 10:59:29,863 @ qz.utils.PrintingUtilities:?
	Returning processor back to pool
@paul-cureton
Copy link
Author

Here is another log using a different qz.configs.create() call:

[DEBUG] 2018-11-20 11:09:09,769 @ qz.ws.PrintSocketClient:?
	Message: {"call":"print","promise":{},"params":{"printer":{"host":"http://<cups-server>/printers/<my-printer>","port":<port>},"options":{"colorType":"color","copies":1,"density":0,"duplex":false,"fallbackDensity":null,"interpolation":"bicubic","jobName":null,"legacy":false,"margins":0,"orientation":null,"paperThickness":null,"printerTray":null,"rasterize":true,"rotation":0,"scaleContent":true,"size":null,"units":"in","altPrinting":false,"encoding":null,"endOfDoc":null,"perSpool":1},"data":["^XA\n","^FO50,100",{"type":"raw","format":"image","data":"https://demo.qz.io/assets/img/image_sample_bw.png","options":{"language":"ZPLII"}},"^FS\n","^FO50,300^ADN,36,20^FDPRINTED USING^FS\n","^FO50,350^ADN,36,20^FDQZ-TRAY ^FS\n","^FO50,400^ADN,36,20^FDVERSION 2.0.7^FS\n\n","^XZ\n"]},"timestamp":1542733749765,"uid":"f28b2w","position":{"x":960,"y":540}}
[WARN] 2018-11-20 11:09:09,772 @ qz.ws.PrintSocketClient:?
	Bad signature on request
[DEBUG] 2018-11-20 11:09:09,782 @ qz.common.TrayManager:?
	Calculated dialog centered at: java.awt.Point[x=680,y=467]
[INFO] 2018-11-20 11:09:11,640 @ qz.common.TrayManager:?
	Allowed localhost to print to http://<cups-server>/printers/<my-printer>
[TRACE] 2018-11-20 11:09:11,640 @ qz.utils.PrintingUtilities:?
	Waiting for processor, 0/1 already in use
[DEBUG] 2018-11-20 11:09:11,641 @ qz.utils.PrintingUtilities:?
	Using qz.printer.action.PrintRaw to print
[WARN] 2018-11-20 11:09:11,641 @ qz.printer.PrintOptions:?
	Cannot read null as a double for fallbackDensity, using default
[INFO] 2018-11-20 11:09:11,949 @ qz.printer.ImageWrapper:?
	Loading BufferedImage
[INFO] 2018-11-20 11:09:11,950 @ qz.printer.ImageWrapper:?
	Dimensions: 256x128
[INFO] 2018-11-20 11:09:11,951 @ qz.printer.ImageWrapper:?
	Initializing Image Fields
[INFO] 2018-11-20 11:09:11,952 @ qz.printer.ImageWrapper:?
	Converting image to monochrome
[INFO] 2018-11-20 11:09:11,982 @ qz.printer.ImageWrapper:?
	Packing bits
[DEBUG] 2018-11-20 11:09:11,991 @ qz.printer.action.PrintRaw:?
	Printing to host http://<cups-server>/printers/<my-printer>
[ERROR] 2018-11-20 11:09:12,002 @ qz.utils.PrintingUtilities:?
	Failed to print
javax.print.PrintException: java.net.UnknownHostException: http://<cups-server>/printers/<my-printer>
	at qz.printer.action.PrintRaw.print(Unknown Source)
	at qz.utils.PrintingUtilities.processPrintRequest(Unknown Source)
	at qz.ws.PrintSocketClient.processMessage(Unknown Source)
	at qz.ws.PrintSocketClient.onMessage(Unknown Source)
	at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
	at java.lang.reflect.Method.invoke(Method.java:508)
	at org.eclipse.jetty.websocket.common.events.annotated.CallableMethod.call(CallableMethod.java:70)
	at org.eclipse.jetty.websocket.common.events.annotated.OptionalSessionCallableMethod.call(OptionalSessionCallableMethod.java:68)
	at org.eclipse.jetty.websocket.common.events.JettyAnnotatedEventDriver$2.run(JettyAnnotatedEventDriver.java:210)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
	at java.lang.Thread.run(Thread.java:812)
Caused by: java.net.UnknownHostException: http://<cups-server>/printers/<my-printer>
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:214)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
	at java.net.Socket.connect(Socket.java:666)
	at java.net.Socket.connect(Socket.java:606)
	at java.net.Socket.<init>(Socket.java:469)
	at java.net.Socket.<init>(Socket.java:239)
	at qz.printer.action.PrintRaw.printToHost(Unknown Source)
	... 13 more
[TRACE] 2018-11-20 11:09:12,007 @ qz.utils.PrintingUtilities:?
	Returning processor back to pool

@tresf
Copy link
Contributor

tresf commented Nov 20, 2018

Correct, this is not supported.

The underlying Java Socket implementation that is used does not provide support for HTTP endpoints.

/**
* A brute-force, however surprisingly elegant way to send a file to a networked printer.
* <p/>
* Please note that this will completely bypass the Print Spooler,
* so the Operating System will have absolutely no printer information.
* This is printing "blind".
*/
private void printToHost(String host, int port, byte[] cmds) throws IOException {
log.debug("Printing to host {}:{}", host, port);
//throws any exception and auto-closes socket and stream
try(Socket socket = new Socket(host, port); DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
out.write(cmds);
}
}

In this case host is a network address as defined by either a resolvable hostname or an IP4/IP6 style address. It's a raw socket and because of that, the standard routing you'd expect from a full blown web server is naturally invalid by context.

To properly support URLs we would need to add URL support to the API. Here's an example from Oracle:

import java.net.*;
import java.io.*;

public class URLConnectionReader {
    public static void main(String[] args) throws Exception {
        URL oracle = new URL("http://www.oracle.com/");
        URLConnection yc = oracle.openConnection();
        BufferedReader in = new BufferedReader(new InputStreamReader(
                                    yc.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null) 
            System.out.println(inputLine);
        in.close();
    }
}

The API would have to change slightly, we'd need to expand the printer to accept a URL. e.g.

var config = qz.configs.create({ url: "http://path/to/some/endpoint", port: 9100 });

@tresf tresf changed the title Unable to print to CUPS URL Ability to print to CUPS URL Nov 29, 2018
@tresf tresf added this to the 2.2 milestone Nov 29, 2018
@tresf
Copy link
Contributor

tresf commented Mar 16, 2021

@arpaulnet hi, I'm not sure if you're still actively using QZ Tray, but if so, do you mind testing the new socket feature for this purpose? #750

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants