OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "printing/backend/print_backend.h" | 5 #include "printing/backend/print_backend.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #if !defined(OS_MACOSX) | 9 #if !defined(OS_MACOSX) |
10 #include <gcrypt.h> | 10 #include <gcrypt.h> |
11 #endif | 11 #endif |
12 #include <pthread.h> | 12 #include <pthread.h> |
13 | 13 |
14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
16 #include "base/lock.h" | 16 #include "base/lock.h" |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/string_number_conversions.h" | 18 #include "base/string_number_conversions.h" |
19 #include "base/values.h" | 19 #include "base/values.h" |
20 #include "googleurl/src/gurl.h" | 20 #include "googleurl/src/gurl.h" |
21 #include "printing/backend/cups_helper.h" | 21 #include "printing/backend/cups_helper.h" |
| 22 #include "printing/backend/print_backend_consts.h" |
22 | 23 |
23 #if !defined(OS_MACOSX) | 24 #if !defined(OS_MACOSX) |
24 GCRY_THREAD_OPTION_PTHREAD_IMPL; | 25 GCRY_THREAD_OPTION_PTHREAD_IMPL; |
25 | 26 |
26 namespace { | 27 namespace { |
27 | 28 |
28 // Init GCrypt library (needed for CUPS) using pthreads. | 29 // Init GCrypt library (needed for CUPS) using pthreads. |
29 // There exists a bug in CUPS library, where it crashed with: "ath.c:184: | 30 // There exists a bug in CUPS library, where it crashed with: "ath.c:184: |
30 // _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed." | 31 // _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed." |
31 // It happened when multiple threads tried printing simultaneously. | 32 // It happened when multiple threads tried printing simultaneously. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 static base::LazyInstance<GcryptInitializer> g_gcrypt_initializer( | 70 static base::LazyInstance<GcryptInitializer> g_gcrypt_initializer( |
70 base::LINKER_INITIALIZED); | 71 base::LINKER_INITIALIZED); |
71 | 72 |
72 } // namespace | 73 } // namespace |
73 #endif | 74 #endif |
74 | 75 |
75 namespace printing { | 76 namespace printing { |
76 | 77 |
77 static const char kCUPSPrinterInfoOpt[] = "printer-info"; | 78 static const char kCUPSPrinterInfoOpt[] = "printer-info"; |
78 static const char kCUPSPrinterStateOpt[] = "printer-state"; | 79 static const char kCUPSPrinterStateOpt[] = "printer-state"; |
79 static const char kCUPSPrintServerURL[] = "print_server_url"; | |
80 | 80 |
81 class PrintBackendCUPS : public PrintBackend { | 81 class PrintBackendCUPS : public PrintBackend { |
82 public: | 82 public: |
83 explicit PrintBackendCUPS(const GURL& print_server_url); | 83 PrintBackendCUPS(const GURL& print_server_url, bool blocking); |
84 virtual ~PrintBackendCUPS() {} | 84 virtual ~PrintBackendCUPS() {} |
85 | 85 |
86 // PrintBackend implementation. | 86 // PrintBackend implementation. |
87 virtual void EnumeratePrinters(PrinterList* printer_list); | 87 virtual void EnumeratePrinters(PrinterList* printer_list); |
88 | 88 |
89 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, | 89 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, |
90 PrinterCapsAndDefaults* printer_info); | 90 PrinterCapsAndDefaults* printer_info); |
91 | 91 |
92 virtual bool IsValidPrinter(const std::string& printer_name); | 92 virtual bool IsValidPrinter(const std::string& printer_name); |
93 | 93 |
94 private: | 94 private: |
95 // Following functions are wrappers around corresponding CUPS functions. | 95 // Following functions are wrappers around corresponding CUPS functions. |
96 // <functions>2() are called when print server is specified, and plain | 96 // <functions>2() are called when print server is specified, and plain |
97 // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT | 97 // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT |
98 // in the <functions>2(), it does not work in CUPS prior to 1.4. | 98 // in the <functions>2(), it does not work in CUPS prior to 1.4. |
99 int GetDests(cups_dest_t** dests); | 99 int GetDests(cups_dest_t** dests); |
100 FilePath GetPPD(const char* name); | 100 FilePath GetPPD(const char* name); |
101 | 101 |
102 GURL print_server_url_; | 102 GURL print_server_url_; |
| 103 bool blocking_; |
103 }; | 104 }; |
104 | 105 |
105 PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url) | 106 PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url, bool blocking) |
106 : print_server_url_(print_server_url) { | 107 : print_server_url_(print_server_url), blocking_(blocking) { |
107 } | 108 } |
108 | 109 |
109 void PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) { | 110 void PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) { |
110 DCHECK(printer_list); | 111 DCHECK(printer_list); |
111 printer_list->clear(); | 112 printer_list->clear(); |
112 | 113 |
113 cups_dest_t* destinations = NULL; | 114 cups_dest_t* destinations = NULL; |
114 int num_dests = GetDests(&destinations); | 115 int num_dests = GetDests(&destinations); |
115 | 116 |
116 for (int printer_index = 0; printer_index < num_dests; printer_index++) { | 117 for (int printer_index = 0; printer_index < num_dests; printer_index++) { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 return false; | 188 return false; |
188 } | 189 } |
189 | 190 |
190 scoped_refptr<PrintBackend> PrintBackend::CreateInstance( | 191 scoped_refptr<PrintBackend> PrintBackend::CreateInstance( |
191 const DictionaryValue* print_backend_settings) { | 192 const DictionaryValue* print_backend_settings) { |
192 #if !defined(OS_MACOSX) | 193 #if !defined(OS_MACOSX) |
193 // Initialize gcrypt library. | 194 // Initialize gcrypt library. |
194 g_gcrypt_initializer.Get(); | 195 g_gcrypt_initializer.Get(); |
195 #endif | 196 #endif |
196 | 197 |
197 std::string print_server_url_str; | 198 std::string print_server_url_str, cups_blocking; |
198 if (print_backend_settings) { | 199 if (print_backend_settings) { |
199 print_backend_settings->GetString(kCUPSPrintServerURL, | 200 print_backend_settings->GetString(kCUPSPrintServerURL, |
200 &print_server_url_str); | 201 &print_server_url_str); |
| 202 |
| 203 print_backend_settings->GetString(kCUPSBlocking, |
| 204 &cups_blocking); |
201 } | 205 } |
202 GURL print_server_url(print_server_url_str.c_str()); | 206 GURL print_server_url(print_server_url_str.c_str()); |
203 return new PrintBackendCUPS(print_server_url); | 207 return new PrintBackendCUPS(print_server_url, cups_blocking == kValueTrue); |
204 } | 208 } |
205 | 209 |
206 int PrintBackendCUPS::GetDests(cups_dest_t** dests) { | 210 int PrintBackendCUPS::GetDests(cups_dest_t** dests) { |
207 if (print_server_url_.is_empty()) { // Use default (local) print server. | 211 if (print_server_url_.is_empty()) { // Use default (local) print server. |
208 return cupsGetDests(dests); | 212 return cupsGetDests(dests); |
209 } else { | 213 } else { |
210 HttpConnectionCUPS http(print_server_url_); | 214 HttpConnectionCUPS http(print_server_url_); |
| 215 http.SetBlocking(blocking_); |
211 return cupsGetDests2(http.http(), dests); | 216 return cupsGetDests2(http.http(), dests); |
212 } | 217 } |
213 } | 218 } |
214 | 219 |
215 FilePath PrintBackendCUPS::GetPPD(const char* name) { | 220 FilePath PrintBackendCUPS::GetPPD(const char* name) { |
216 // cupsGetPPD returns a filename stored in a static buffer in CUPS. | 221 // cupsGetPPD returns a filename stored in a static buffer in CUPS. |
217 // Protect this code with lock. | 222 // Protect this code with lock. |
218 static Lock ppd_lock; | 223 static Lock ppd_lock; |
219 AutoLock ppd_autolock(ppd_lock); | 224 AutoLock ppd_autolock(ppd_lock); |
220 FilePath ppd_path; | 225 FilePath ppd_path; |
221 const char* ppd_file_path = NULL; | 226 const char* ppd_file_path = NULL; |
222 if (print_server_url_.is_empty()) { // Use default (local) print server. | 227 if (print_server_url_.is_empty()) { // Use default (local) print server. |
223 ppd_file_path = cupsGetPPD(name); | 228 ppd_file_path = cupsGetPPD(name); |
224 if (ppd_file_path) | 229 if (ppd_file_path) |
225 ppd_path = FilePath(ppd_file_path); | 230 ppd_path = FilePath(ppd_file_path); |
226 } else { | 231 } else { |
227 // cupsGetPPD2 gets stuck sometimes in an infinite time due to network | 232 // cupsGetPPD2 gets stuck sometimes in an infinite time due to network |
228 // configuration/issues. To prevent that, use non-blocking http connection | 233 // configuration/issues. To prevent that, use non-blocking http connection |
229 // here. | 234 // here. |
230 // Note: After looking at CUPS sources, it looks like non-blocking | 235 // Note: After looking at CUPS sources, it looks like non-blocking |
231 // connection will timeout after 10 seconds of no data period. And it will | 236 // connection will timeout after 10 seconds of no data period. And it will |
232 // return the same way as if data was completely and sucessfully downloaded. | 237 // return the same way as if data was completely and sucessfully downloaded. |
233 // To distinguish error case from the normal return, will check result file | 238 // To distinguish error case from the normal return, will check result file |
234 // size agains content length. | 239 // size agains content length. |
235 HttpConnectionCUPS http(print_server_url_); | 240 HttpConnectionCUPS http(print_server_url_); |
236 http.SetBlocking(false); | 241 http.SetBlocking(blocking_); |
237 ppd_file_path = cupsGetPPD2(http.http(), name); | 242 ppd_file_path = cupsGetPPD2(http.http(), name); |
238 // Check if the get full PPD, since non-blocking call may simply return | 243 // Check if the get full PPD, since non-blocking call may simply return |
239 // normally after timeout expired. | 244 // normally after timeout expired. |
240 if (ppd_file_path) { | 245 if (ppd_file_path) { |
241 ppd_path = FilePath(ppd_file_path); | 246 ppd_path = FilePath(ppd_file_path); |
242 off_t content_len = httpGetLength2(http.http()); | 247 off_t content_len = httpGetLength2(http.http()); |
243 int64 ppd_size = 0; | 248 int64 ppd_size = 0; |
244 // This is a heuristic to detect if we reached timeout. If we see content | 249 // This is a heuristic to detect if we reached timeout. If we see content |
245 // length is larger that the actual file we downloaded it means timeout | 250 // length is larger that the actual file we downloaded it means timeout |
246 // reached. Sometimes http can be compressed, and in that case the | 251 // reached. Sometimes http can be compressed, and in that case the |
247 // the content length will be smaller than the actual payload (not sure | 252 // the content length will be smaller than the actual payload (not sure |
248 // if CUPS support such responses). | 253 // if CUPS support such responses). |
249 if (!file_util::GetFileSize(ppd_path, &ppd_size) || | 254 if (!file_util::GetFileSize(ppd_path, &ppd_size) || |
250 content_len > ppd_size) { | 255 content_len > ppd_size) { |
251 LOG(ERROR) << "Error downloading PPD file for: " << name | 256 LOG(ERROR) << "Error downloading PPD file for: " << name |
252 << ", file size: " << ppd_size | 257 << ", file size: " << ppd_size |
253 << ", content length: " << content_len; | 258 << ", content length: " << content_len; |
254 file_util::Delete(ppd_path, false); | 259 file_util::Delete(ppd_path, false); |
255 ppd_path.clear(); | 260 ppd_path.clear(); |
256 } | 261 } |
257 } | 262 } |
258 } | 263 } |
259 return ppd_path; | 264 return ppd_path; |
260 } | 265 } |
261 | 266 |
262 } // namespace printing | 267 } // namespace printing |
OLD | NEW |