| 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 |