Privet یک API کشف محلی Cloud Device است که توسط سرویس های ابری استفاده می شود. این سند در بخش های زیر سازماندهی شده است:
- مقدمه : مقدمه ای بر Privet
- کشف : مکانیسم های کشف محلی
- اطلاعیه ها : اعلامیه های کشف محلی
- API : API های Privet برای دستگاه های ابری عمومی
- API چاپگر: API های Privet که توسط چاپگرها استفاده می شود
- پیوست : نمودارهای تکمیلی
1. مقدمه
دستگاه های متصل به ابر مزایای بسیاری دارند. آنها میتوانند از خدمات تبدیل آنلاین استفاده کنند، در حالی که دستگاه آفلاین است میزبان صفهای شغلی باشند و از هر نقطهای در جهان قابل دسترسی باشند. با این حال، با بسیاری از دستگاههای ابری که توسط یک کاربر خاص قابل دسترسی هستند، باید روشی برای یافتن نزدیکترین دستگاه بر اساس موقعیت مکانی ارائه کنیم. هدف از پروتکل Privet این است که انعطاف پذیری دستگاه های ابری را با مکانیزم کشف محلی مناسب پیوند دهد تا دستگاه ها به راحتی در محیط های جدید کشف شوند.
اهداف این پروتکل عبارتند از:- دستگاه های ابری را به صورت محلی قابل شناسایی کنید
- دستگاه های ابری را با یک سرویس ابری ثبت کنید
- دستگاه های ثبت شده را با نمایش ابری آنها مرتبط کنید
- فعال کردن عملکرد آفلاین
- پیاده سازی را ساده کنید تا دستگاه های کوچک بتوانند از آن استفاده کنند
پروتکل Privet از 2 بخش اصلی تشکیل شده است: کشف و API. Discovery برای یافتن دستگاه در شبکه محلی و API برای دریافت اطلاعات در مورد دستگاه و انجام برخی اقدامات استفاده می شود. در سراسر این سند، دستگاه به یک دستگاه متصل به ابر که پروتکل Privet را اجرا می کند، اشاره دارد.
2. کشف
Discovery یک پروتکل مبتنی بر zeroconf (mDNS + DNS-SD) است. دستگاه باید IPv4 Link-Local Addressing را پیاده سازی کند. دستگاه باید با مشخصات mDNS و DNS-SD مطابقت داشته باشد.
- http://www.rfc-editor.org/rfc/rfc3927.txt (IPv4 Link-local)
- http://www.rfc-editor.org/rfc/rfc4862.txt (IPv6 Link-local)
- http://www.rfc-editor.org/rfc/rfc6762.txt (mDNS)
- http://www.rfc-editor.org/rfc/rfc6763.txt (DNS-SD)
دستگاه باید مطابق با مشخصات بالا حل تعارض نام را انجام دهد.
2.1. نوع خدمات
DNS Service Discovery از قالب زیر برای انواع سرویس استفاده می کند: _applicationprotocol._transportprotocol . در مورد پروتکل Privet، نوع سرویس برای DNS-SD باید این باشد: _privet._tcp
این دستگاه می تواند انواع خدمات دیگر را نیز پیاده سازی کند. توصیه می شود از نام نمونه سرویس یکسانی برای همه انواع سرویس های پیاده سازی شده توسط دستگاه استفاده کنید. به عنوان مثال: یک چاپگر ممکن است خدمات "Printer XYZ._privet._tcp" و "Printer XYZ._printer._tcp" را اجرا کند. راه اندازی را برای کاربر ساده می کند. با این حال، مشتریان Privet فقط به دنبال "_privet._tcp" خواهند بود.
علاوه بر نوع سرویس اصلی، دستگاه باید سوابق PTR را برای نوع(های) فرعی مربوطه خود تبلیغ کند (مشخصات DNS-SD را ببینید: "7.1. انتخابی نمونه های انتخابی (Subtypes)"). قالب باید به شرح زیر باشد: _<subtype>._sub._privet._tcp
در حال حاضر تنها نوع فرعی دستگاه پشتیبانی شده چاپگر است. بنابراین، همه چاپگرها باید دو رکورد PTR را تبلیغ کنند:
- _privet._tcp.local.
- _printer._sub._privet._tcp.local.
2.2. رکورد TXT
DNS Service Discovery فیلدهایی را برای افزودن اطلاعات اختیاری در مورد یک سرویس در رکوردهای TXT تعریف می کند. یک رکورد TXT از جفت کلید/مقدار تشکیل شده است. هر جفت کلید/مقدار از طول بایت شروع می شود و تا 255 بایت متن شروع می شود. کلید متن قبل از اولین کاراکتر '=' و مقدار آن متن بعد از اولین کاراکتر '=' تا پایان است. مشخصات اجازه نمی دهد تا هیچ مقداری در رکورد وجود نداشته باشد، در چنین حالتی هیچ کاراکتر '=' یا بدون متن بعد از کاراکتر '=' وجود نخواهد داشت. (مشخصات DNS-SD را ببینید: "6.1. قوانین فرمت عمومی برای رکوردهای DNS TXT" برای فرمت رکورد DNS TXT و "6.2. DNS-SD TXT Record Size" برای طول توصیه شده).
Privet به دستگاه نیاز دارد که جفت کلید/مقدار زیر را در رکورد TXT ارسال کند. رشته های کلید/مقدار به حروف بزرگ و کوچک حساس نیستند، برای مثال «CS=online» و «cs=ONLINE» یکسان هستند. اطلاعات موجود در رکورد TXT باید همان اطلاعاتی باشد که از طریق /info API قابل دسترسی است (به بخش API 4.1 مراجعه کنید).
توصیه می شود اندازه رکورد TXT را زیر 512 بایت نگه دارید.
2.2.1. txtvers
نسخه ساختار TXT. txtvers باید اولین رکورد ساختار TXT باشد. در حال حاضر تنها نسخه پشتیبانی شده 1 است.
txtvers=1
2.2.2. ty
یک نام قابل خواندن برای کاربر از دستگاه ارائه می دهد. مثلا:
ty=Google Cloud Ready Printer Model XYZ
2.2.3. یادداشت (اختیاری)
یک نام قابل خواندن برای کاربر از دستگاه ارائه می دهد. مثلا:
note=1st floor lobby printer
توجه: این یک کلید اختیاری است و ممکن است از آن صرفنظر شود. با این حال، در صورت وجود، کاربر باید بتواند این مقدار را تغییر دهد. هنگام ثبت نام دستگاه باید از همین شرح استفاده شود.
2.2.4. آدرس اینترنتی
نشانی وب سرور این دستگاه (شامل پروتکل) به آن متصل است. مثلا:
url=https://www.google.com/cloudprint
2.2.5. نوع
فهرستی از انواع فرعی دستگاه که توسط این دستگاه پشتیبانی می شود، جدا شده با کاما. قالب این است: "type=_subtype1,_subtype2". در حال حاضر، تنها نوع فرعی دستگاه پشتیبانی شده چاپگر است.
type=printer
هر زیرنوع فهرست شده باید با استفاده از یک رکورد PTR مربوطه تبلیغ شود. برای هر زیرنوع سرویس پشتیبانی شده، باید یک مورد مربوطه وجود داشته باشد. نام نوع فرعی سرویس (<subtype>._sub._privet._tcp) باید با نوع دستگاه در اینجا برابر باشد.
2.2.6. شناسه
شناسه دستگاه. اگر دستگاه هنوز ثبت نشده است، این کلید باید وجود داشته باشد، اما مقدار باید خالی باشد. مثلا:
id=11111111-2222-3333-4444-555555555555 id=
2.2.7. cs
وضعیت اتصال فعلی دستگاه را نشان می دهد. چهار مقدار ممکن در این مشخصات تعریف شده است.
- "آنلاین" نشان می دهد که دستگاه در حال حاضر به ابر متصل است.
- "آفلاین" نشان می دهد که دستگاه در شبکه محلی در دسترس است، اما نمی تواند با سرور صحبت کند.
- "اتصال" نشان می دهد که دستگاه در حال انجام دنباله راه اندازی خود است و هنوز به طور کامل آنلاین نیست.
- "not-configured" نشان می دهد که دسترسی به اینترنت دستگاه هنوز پیکربندی نشده است. این مقدار در حال حاضر استفاده نمی شود، اما ممکن است در نسخه های بعدی مشخصات مفید باشد.
- cs=آنلاین
- cs=آفلاین
- cs=اتصال
اگر دستگاه با یک ابر ثبت شده است، هنگام راه اندازی باید اتصال با یک سرور را برای تشخیص وضعیت اتصال آن بررسی کند (به عنوان مثال، فراخوانی API ابری برای دریافت تنظیمات دستگاه). دستگاه ممکن است از وضعیت اتصال کانال اعلانات خود (به عنوان مثال XMPP) برای گزارش این مقدار استفاده کند. دستگاههای ثبتنشده هنگام راهاندازی ممکن است یک دامنه را برای تشخیص وضعیت اتصال آنها پینگ کنند (برای مثال، پینگ www.google.com برای دستگاههای چاپ ابری).
3. اطلاعیه ها
هنگام راه اندازی، خاموش شدن یا تغییر وضعیت دستگاه، دستگاه باید مرحله اعلام را همانطور که در مشخصات mDNS توضیح داده شده است انجام دهد. باید اطلاعیه مربوطه را حداقل دو بار با فاصله حداقل یک ثانیه بین آنها ارسال کند.
3.1. استارت آپ
هنگام راهاندازی دستگاه، باید مراحل بررسی و اعلام را همانطور که در مشخصات mDNS توضیح داده شده است انجام دهد. رکوردهای SRV، PTR و TXT باید در این مورد ارسال شوند. توصیه می شود در صورت امکان همه رکوردها را در یک پاسخ DNS گروه بندی کنید. اگر نه، ترتیب زیر توصیه می شود: رکوردهای SRV، PTR، TXT.
3.2. خاموش شدن
هنگام خاموش شدن دستگاه، باید سعی کند با ارسال یک "بسته خداحافظی" با TTL=0 (همانطور که در مستندات mDNS توضیح داده شده است) همه طرف های علاقه مند را در مورد آن مطلع کند.
3.3. به روز رسانی
در صورتی که هر گونه اطلاعات توضیح داده شده در TXT تغییر کرده باشد، دستگاه باید اعلامیه به روز رسانی ارسال کند. فقط کافی است رکورد جدید TXT را در این مورد ارسال کنید. به عنوان مثال، پس از ثبت نام دستگاه، باید یک اعلامیه به روز رسانی شامل شناسه دستگاه جدید ارسال کند.
4. API
پس از کشف یک دستگاه ابری، ارتباط مشتری با دستگاه مستقیماً از طریق شبکه محلی فعال می شود. همه API ها مبتنی بر HTTP 1.1 هستند. فرمت های داده مبتنی بر JSON هستند. درخواستهای API ممکن است درخواستهای GET یا POST باشند.
هر درخواست باید حاوی یک هدر معتبر " X-Privet-Token " باشد. تنها درخواستی که مجاز به داشتن سرصفحه خالی "X-Privet-Token" است، درخواست /privet/info است (توجه داشته باشید که هدر باید همچنان وجود داشته باشد). اگر هدر "X-Privet-Token" وجود نداشته باشد، دستگاه باید با خطای HTTP 400 زیر پاسخ دهد:
HTTP/1.1 400 Missing X-Privet-Token header.
اگر سرصفحه "X-Privet-Token" خالی یا نامعتبر است، دستگاه باید با "خطای نامعتبر X-Privet-Token" پاسخ دهد (invalid_x_privet_token، برای جزئیات بیشتر به بخش خطاها مراجعه کنید). تنها استثنا API /info است. برای مشاهده اطلاعات بیشتر در مورد اینکه چرا این کار انجام می شود و چگونه باید توکن ها تولید شوند، به پیوست A: حملات و پیشگیری XSSI و XSRF مراجعه کنید.
اگر یک API درخواستی وجود نداشته باشد یا پشتیبانی نشود، دستگاه باید یک خطای HTTP 404 را برگرداند.
4.1. در دسترس بودن API
قبل از نمایش هر API (از جمله /info API)، دستگاه باید برای بررسی تنظیمات محلی با سرور تماس بگیرد. تنظیمات محلی باید بین راه اندازی مجدد حفظ شود. اگر سرور در دسترس نباشد، باید از آخرین تنظیمات محلی شناخته شده استفاده شود. اگر دستگاه هنوز ثبت نشده است، باید تنظیمات پیش فرض را انجام دهد.
دستگاههای Cloud Print برای ثبت، دریافت و بهروزرسانی تنظیمات محلی باید مراحل زیر را دنبال کنند.
4.1.1. ثبت
هنگامی که دستگاه ثبت می شود، باید پارامتر "local_settings" را به شرح زیر مشخص کند:
{ "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 } }تنظیمات زیر را می توان تنظیم کرد:
نام ارزش | نوع ارزش | شرح |
---|---|---|
محلی_کشف | بولی | نشان می دهد که آیا عملکرد کشف محلی مجاز است یا خیر. اگر "نادرست" باشد، همه APIهای محلی (از جمله /info) و کشف DNS-SD باید غیرفعال شوند. بهطور پیشفرض، دستگاههای ثبتشده جدید باید «درست» را بگذرانند. |
access_token_enabled | بولی (اختیاری) | نشان می دهد که آیا /accesstoken API باید در شبکه محلی در معرض دید قرار گیرد. به طور پیش فرض باید "درست" باشد. |
printer/local_printing_enabled | بولی (اختیاری) | نشان می دهد که آیا عملکرد چاپ محلی (/printer/createjob، /printer/submitdoc، /printer/jobstate) باید در شبکه محلی نمایش داده شود یا خیر. به طور پیش فرض باید "درست" باشد. |
printer/conversion_printing_enabled | بولی (اختیاری) | نشان می دهد که آیا چاپ محلی ممکن است کار را برای تبدیل به سرور ارسال کند یا خیر. فقط زمانی معنا پیدا می کند که چاپ محلی فعال باشد. |
xmpp_timeout_value | int (اختیاری) | تعداد ثانیه های بین پینگ های کانال XMPP را نشان می دهد. به طور پیش فرض باید 300 (5 دقیقه) یا بیشتر باشد. |
مهم: فقدان مقدار اختیاری نشان می دهد که عملکرد مربوطه به طور کامل توسط دستگاه پشتیبانی نمی شود.
4.1.2. استارت آپ
هنگام راهاندازی دستگاه، باید با سرور تماس بگیرد تا بررسی کند چه APIهایی برای نمایش در شبکه محلی موجود است. برای چاپگرهای متصل به Cloud Print، آنها باید تماس بگیرند:
/cloudprint/printer?printerid=<printer_id>یا
/cloudprint/list
/cloudprint/printer بر /cloudprint/list ترجیح داده می شود، اما هر دو کار خواهند کرد.
این API پارامترهای دستگاه فعلی، از جمله تنظیمات API محلی را برمی گرداند. پاسخ سرور به شکل زیر خواهد بود:
"local_settings": { "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 }, "pending": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": false, "printer/conversion_printing_enabled": false, "xmpp_timeout_value": 500 } }
شیء "current" تنظیماتی را نشان می دهد که در حال حاضر در حال اجرا هستند.
شیء "pending" تنظیماتی را نشان می دهد که باید روی دستگاه اعمال شود (این شی ممکن است وجود نداشته باشد).
هنگامی که دستگاه تنظیمات "در انتظار" را مشاهده کرد، باید وضعیت خود را به روز کند (به زیر مراجعه کنید).
4.1.3. به روز رسانی
در صورت نیاز به به روز رسانی تنظیمات، یک اعلان XMPP به دستگاه ارسال می شود. این اطلاعیه در قالب زیر خواهد بود:
<device_id>/update_settings
با دریافت چنین اعلانی، دستگاه باید از سرور درخواست کند تا آخرین تنظیمات را دریافت کند. دستگاه های Cloud Print باید از موارد زیر استفاده کنند:
/cloudprint/printer?printerid=<printer_id>
هنگامی که دستگاه بخش "در انتظار" را در نتیجه API /cloudprint/printer (در هنگام راه اندازی یا به دلیل اعلان) مشاهده کرد، باید وضعیت داخلی خود را به روز کند تا تنظیمات جدید را به خاطر بسپارد. برای تأیید تنظیمات جدید باید با API سرور تماس بگیرد. برای چاپگرهای ابری، دستگاه باید /cloudprint/update API را فراخوانی کند و مانند هنگام ثبت نام از پارامتر "local_settings" استفاده کند.
هنگام اتصال مجدد به کانال XMPP، دستگاه باید /cloudprint/printer API را صدا کند تا بررسی کند آیا تنظیمات محلی از آخرین بار تغییر کرده است یا خیر.
4.1.3.1. تنظیمات محلی در انتظار
پارامتر "local_settings" که دستگاه برای فراخوانی API سرور استفاده می کند، هرگز نباید دارای بخش "در انتظار" باشد.
4.1.3.2. تنظیمات محلی فعلی
فقط دستگاه میتواند بخش "current" در "local_settings" را تغییر دهد. هر کس دیگری بخش "در انتظار" را تغییر خواهد داد، و منتظر بمانید تا تغییرات توسط دستگاه به بخش "جاری" منتشر شود.
4.1.4. آفلاین
در صورت عدم امکان تماس با سرور در حین راه اندازی، پس از اعلان، دستگاه باید از آخرین تنظیمات محلی شناخته شده استفاده کند.
4.1.5. حذف دستگاه از سرویس
اگر دستگاه از سرویس حذف شده باشد (به عنوان مثال GCP)، یک اعلان XMPP به دستگاه ارسال می شود. این اطلاعیه در قالب زیر خواهد بود:
<device_id>/delete
با دریافت چنین اعلان، دستگاه باید برای بررسی وضعیت خود به سرور مراجعه کند. دستگاه های Cloud Print باید از موارد زیر استفاده کنند:
/cloudprint/printer?printerid=<printer_id>
دستگاه باید یک پاسخ HTTP موفق با موفقیت=نادرست و بدون شرح دستگاه/چاپگر دریافت کند. این بدان معناست که دستگاه از سرور حذف شده است و دستگاه باید اعتبار خود را پاک کند و به حالت تنظیمات کارخانه پیش فرض برود.
هر زمان که دستگاه پاسخی دریافت می کند که نشان می دهد در نتیجه API /cloudprint/printer حذف شده است (راه اندازی، اعلان تنظیمات به روز رسانی، پینگ روزانه)، باید اعتبار خود را حذف کرده و به حالت پیش فرض برود.
4.2. /privet/info API
API اطلاعات اجباری است و باید توسط هر دستگاهی اجرا شود. این یک درخواست HTTP GET برای آدرس اینترنتی "/privet/info" است: GET /privet/info HTTP/1.1
info API اطلاعات اولیه در مورد دستگاه و عملکردی که پشتیبانی می کند را برمی گرداند. این API هرگز نباید وضعیت دستگاه را تغییر دهد یا اقدامی انجام دهد، زیرا در برابر حملات XSRF آسیب پذیر است. این تنها API است که مجاز به داشتن هدر خالی "X-Privet-Token" است. مشتریان باید /privet/info API را با هدر "X-Privet-Token" که روی X-Privet-Token تنظیم شده است تماس بگیرند: ""
API اطلاعات باید دادههای مطابق با دادههای موجود در رکورد TXT را در طول کشف برگرداند.
4.2.1. ورودی
/privet/info API هیچ پارامتر ورودی ندارد.
4.2.2. برگشت
/privet/info API اطلاعات اولیه دستگاه و عملکردهای پشتیبانی شده را برمی گرداند.
ستون TXT فیلد مربوطه را در رکورد DNS-SD TXT نشان می دهد.
نام ارزش | نوع ارزش | شرح | TXT |
---|---|---|---|
نسخه | رشته | بالاترین نسخه (major.minor) API پشتیبانی شده، در حال حاضر 1.0 | |
نام | رشته | نام دستگاه قابل خواندن توسط انسان. | ty |
شرح | رشته | (اختیاری) توضیحات دستگاه. باید توسط کاربر قابل تغییر باشد. | توجه داشته باشید |
آدرس اینترنتی | رشته | URL سروری که این دستگاه با آن صحبت می کند. URL باید شامل مشخصات پروتکل باشد، به عنوان مثال: https://www.google.com/cloudprint. | آدرس اینترنتی |
نوع | لیست رشته ها | لیست انواع دستگاه های پشتیبانی شده | نوع |
شناسه | رشته | شناسه دستگاه، اگر دستگاه هنوز ثبت نشده باشد، خالی شود. | شناسه |
device_state | رشته | وضعیت دستگاه بیکار یعنی دستگاه آماده است پردازش به این معنی است که دستگاه مشغول است و عملکرد ممکن است برای مدتی محدود شود توقف به این معنی است که دستگاه کار نمی کند و مداخله کاربر لازم است | |
حالت اتصال | رشته | وضعیت اتصال به سرور (base_url) آنلاین - اتصال در دسترس است آفلاین - بدون اتصال اتصال - انجام مراحل راه اندازی پیکربندی نشده - اتصال هنوز پیکربندی نشده است یک دستگاه ثبت شده ممکن است وضعیت اتصال خود را بر اساس وضعیت کانال اعلان گزارش دهد (به عنوان مثال وضعیت اتصال XMPP). | cs |
سازنده | رشته | نام سازنده دستگاه | |
مدل | رشته | مدل دستگاه | |
شماره سریال | رشته | شناسه دستگاه منحصر به فرد در این مشخصات، این باید یک UUID باشد. (مشخصات GCP 1.1) (اختیاری) اکیداً توصیه میکنیم از شناسه شماره سریال یکسانی در همه جا استفاده کنید، تا مشتریان مختلف بتوانند دستگاه مشابهی را شناسایی کنند. به عنوان مثال، چاپگرهایی که IPP را پیادهسازی میکنند ممکن است از این شناسه شماره سریال در قسمت "چاپگر-دستگاه-id" استفاده کنند. | |
سیستم عامل | رشته | نسخه سیستم عامل دستگاه | |
زمان کار | بین المللی | تعداد ثانیه از بوت دستگاه. | |
setup_url | رشته | (اختیاری) URL (از جمله پروتکل) صفحه با دستورالعمل های راه اندازی | |
support_url | رشته | (اختیاری) URL (از جمله پروتکل) صفحه با پشتیبانی، اطلاعات پرسش و پاسخ | |
update_url | رشته | (اختیاری) URL (از جمله پروتکل) صفحه با دستورالعمل های به روز رسانی سیستم عامل | |
x-privet-token | رشته | مقدار هدر X-Privet-Token که برای جلوگیری از حملات XSSI و XSRF باید به همه API ها منتقل شود. 6.1 را ببینید. برای جزئیات | |
api | توضیحات API ها | لیست API های پشتیبانی شده (در زیر توضیح داده شده است) | |
حالت_معنایی | JSON | (اختیاری) وضعیت معنایی دستگاه در قالب CloudDeviceState . |
api - یک لیست JSON حاوی لیستی از APIهای موجود از طریق شبکه محلی است. توجه داشته باشید که ممکن است همه APIها به طور همزمان از طریق شبکه محلی در دسترس نباشند. به عنوان مثال، دستگاهی که به تازگی متصل شده است باید فقط از /register api پشتیبانی کند:
"api": [ "/privet/register", ]هنگامی که ثبت دستگاه کامل شد، دستگاه باید پشتیبانی از /register API را متوقف کند. دستگاه همچنین باید با سرویس بررسی کند تا چه API هایی را می توان از طریق شبکه محلی در معرض دید قرار داد. به عنوان مثال:
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
API های زیر در حال حاضر در دسترس هستند:
- /privet/register - API برای ثبت دستگاه در شبکه محلی. (برای جزئیات به /privet/register API مراجعه کنید). این API باید پس از ثبت موفقیت آمیز دستگاه در ابر پنهان شود.
- /privet/accesstoken - API برای درخواست رمز دسترسی از دستگاه (برای جزئیات به /privet/accesstoken API مراجعه کنید).
- /privet/capabilities - API برای بازیابی قابلیتهای دستگاه (برای جزئیات به /privet/capabilities API مراجعه کنید).
- /privet/printer/* - API مخصوص نوع دستگاه "printer"، برای جزئیات بیشتر به APIهای خاص چاپگر مراجعه کنید.
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "idle", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ] }در اینجا نمونه ای از پاسخ /privet/info برای چاپگری است که جوهر آن تمام شده است (به فیلد semantic_state توجه کنید):
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "stopped", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ], "semantic_state": { "version": "1.0", "printer": { "state": "STOPPED", "marker_state": { "item": [ { "vendor_id": "ink", "state": "EXHAUSTED", "level_percent": 0 } ] } } } }
4.2.3. خطاها
API /privet/info فقط در صورتی که هدر X-Privet-Token وجود نداشته باشد باید خطا را برگرداند. باید خطای HTTP 400 باشد:
HTTP/1.1 400 Missing X-Privet-Token header.
4.3. /privet/register API
/privet/register API اختیاری است. این یک درخواست HTTP POST است. /privet/register API باید یک هدر معتبر X-Privet-Token را بررسی کند. دستگاه باید این API را در url "/privet/register" پیاده سازی کند:
POST /privet/register?action=start&user=user@domain.com HTTP/1.1 POST /privet/register?action=complete&user=user@domain.com HTTP/1.1
دستگاه باید /privet/register API را فقط زمانی در معرض نمایش بگذارد که در حال حاضر امکان ثبت نام ناشناس را داشته باشد. مثلا:
- هنگامی که دستگاه روشن است (یا پس از کلیک کردن روی یک دکمه خاص روی دستگاه) و هنوز ثبت نشده است، باید API /privet/register را نشان دهد تا به کاربر از شبکه محلی اجازه دهد تا چاپگر را ادعا کند.
- پس از تکمیل ثبتنام، دستگاه باید نمایش API /privet/register را متوقف کند تا از بازیابی دستگاه توسط کاربر دیگری در شبکه محلی جلوگیری شود.
- برخی از دستگاهها ممکن است روشهای مختلفی برای ثبت دستگاهها داشته باشند و نباید API /privet/register را به هیچ وجه در معرض نمایش قرار دهند (به عنوان مثال، رابط Chrome Cloud Print).
فرآیند ثبت نام شامل 3 مرحله است (به ثبت نام ناشناس برای Cloud Print مراجعه کنید).
- فرآیند ثبت نام ناشناس را آغاز کنید.
- یک کلاینت این فرآیند را با فراخوانی /privet/register API آغاز می کند. ممکن است دستگاه در آن زمان منتظر تأیید کاربر باشد.
- رمز ادعا را دریافت کنید.
مشتری نظرسنجی می کند تا بفهمد دستگاه چه زمانی برای ادامه کار آماده است. پس از آماده شدن دستگاه، درخواستی برای بازیابی رمز ثبت نام و URL ثبت نام به سرور ارسال می کند. رمز دریافتی و URL باید به مشتری بازگردانده شود. در طی این مرحله، اگر دستگاه تماس دیگری برای شروع ثبت نام دریافت کرد، باید:
- اگر این همان کاربری است که ثبت نام را شروع کرده است - تمام داده های قبلی (در صورت وجود) را رها کنید و فرآیند ثبت نام جدید را شروع کنید.
- اگر این کاربر متفاوت است - خطای device_busy و 30 ثانیه پایان زمان را برگردانید.
مراحل ثبت نام را کامل کنید.
پس از اینکه مشتری دستگاه را ادعا کرد، مشتری باید دستگاه را برای تکمیل ثبت نام مطلع کند. پس از تکمیل فرآیند ثبت نام، دستگاه باید یک اعلامیه به روز رسانی، از جمله شناسه دستگاه تازه به دست آمده ارسال کند.
توجه: هنگامی که دستگاه در حال پردازش یک تماس API /privet/register است، هیچ تماس API /privet/register دیگری نمیتواند به طور همزمان پردازش شود. دستگاه باید خطای device_busy و مهلت زمانی 30 ثانیه را برگرداند.
تایید کاربر برای ثبت نام در دستگاه به شدت توصیه می شود. در صورت پیاده سازی، دستگاه باید پس از دریافت یک تماس /privet/register?action=start API منتظر تایید کاربر باشد. مشتری با /privet/register?action=getClaimToken API تماس میگیرد تا از تکمیل تأیید کاربر و در دسترس بودن رمز ادعا مطلع شود. اگر کاربر ثبت نام در دستگاه را لغو کند (مثلاً دکمه لغو را فشار دهد)، خطای user_cancel باید برگردانده شود. اگر کاربر ثبت نام را در بازه زمانی مشخصی تایید نکرده باشد، خطای confirmation_timeout باید برگردانده شود. برای جزئیات بیشتر به بخش پیش فرض ها مراجعه کنید.
4.3.1. ورودی
/privet/register API دارای پارامترهای ورودی زیر است:نام | ارزش |
---|---|
عمل | می تواند یکی از موارد زیر باشد: شروع - برای شروع فرآیند ثبت نام getClaimToken - رمز ادعای دستگاه را بازیابی کنید لغو - برای لغو فرآیند ثبت نام کامل - برای تکمیل فرآیند ثبت نام |
کاربر | ایمیل کاربری که این دستگاه را ادعا می کند. |
دستگاه باید بررسی کند که آدرس ایمیل همه اقدامات (شروع، دریافتClaimToken، لغو، تکمیل) مطابقت داشته باشد.
4.3.2. برگشت
/privet/register API داده های زیر را برمی گرداند:نام ارزش | نوع ارزش | شرح |
---|---|---|
عمل | رشته | عملکرد مشابه در پارامتر ورودی. |
کاربر | رشته (اختیاری) | همان کاربر در پارامتر ورودی (ممکن است وجود نداشته باشد، اگر در ورودی حذف شود). |
نشانه | رشته (اختیاری) | نشانه ثبت نام (اجباری برای پاسخ "getClaimToken"، برای "شروع"، "کامل"، "لغو" حذف شده است). |
ادعا_url | رشته (اختیاری) | URL ثبت نام (اجباری برای پاسخ "getClaimToken"، برای "شروع"، "کامل"، "لغو" حذف شده است). برای چاپگرهای ابری باید "complete_invite_url" دریافت شده از سرور باشد. |
automated_claim_url | رشته (اختیاری) | URL ثبت نام (اجباری برای پاسخ "getClaimToken"، برای "شروع"، "کامل"، "لغو" حذف شده است). برای چاپگرهای ابری باید "automated_invite_url" دریافت شده از سرور باشد. |
شناسه دستگاه | رشته (اختیاری) | شناسه دستگاه جدید (برای پاسخ "شروع" حذف شده است، برای "کامل" اجباری است). |
دستگاه باید فقط پس از تکمیل ثبت نام، شناسه دستگاه خود را در پاسخ API /privet/info برگرداند.
مثال 1:
{ "action": "start", "user": "user@domain.com", }
مثال 2:
{ "action": "getClaimToken", "user": "user@domain.com", "token": "AAA111222333444555666777", "claim_url": "https://domain.com/SoMeUrL", }
مثال 3:
{ "action": "complete", "user": "user@domain.com", "device_id": "11111111-2222-3333-4444-555555555555", }
4.3.3. خطاها
/privet/register API ممکن است خطاهای زیر را برگرداند (برای جزئیات به بخش خطاها مراجعه کنید):خطا | شرح |
---|---|
device_busy | دستگاه مشغول است و نمی تواند عمل درخواستی را انجام دهد. پس از اتمام زمان، دوباره تلاش کنید. |
pending_user_action | در پاسخ به "getClaimToken" این خطا نشان می دهد که دستگاه هنوز در انتظار تایید کاربر است و درخواست "getClaimToken" باید پس از اتمام زمان دوباره امتحان شود. |
user_cancel | کاربر به صراحت فرآیند ثبت نام را از دستگاه لغو کرد. |
confirmation_timeout | زمان تایید کاربر تمام می شود. |
invalid_action | عمل نامعتبر نامیده می شود. برای مثال، اگر کلاینت قبل از فراخوانی action=start و action=getClaimToken را فراخوانی کند. |
invalid_params | پارامترهای نامعتبر مشخص شده در درخواست. (پارامترهای ناشناخته باید با خیال راحت برای سازگاری در آینده نادیده گرفته شوند). برای مثال، اگر کلاینت action=unknown یا user= نامیده است، این را برگردانید. |
device_config_error | تاریخ/زمان (یا برخی تنظیمات دیگر) در سمت دستگاه اشتباه است. کاربر باید برود (به وب سایت داخلی دستگاه) و تنظیمات دستگاه را پیکربندی کند. |
آفلاین | دستگاه در حال حاضر آفلاین است و نمی تواند با سرور صحبت کند. |
خطای سرور | خطای سرور در هنگام ثبت نام |
invalid_x_privet_token | X-Privet-Token در درخواست نامعتبر یا خالی است. |
پس از اینکه ثبت نام با موفقیت انجام شد، دستگاه باید افشای /privet/register API را متوقف کند. اگر دستگاه API /privet/register را نمایش نمیدهد، باید خطای HTTP 404 را برگرداند. بنابراین، اگر دستگاهی قبلاً ثبت شده است، فراخوانی این API باید 404 را برگرداند. اگر هدر X-Privet-Token وجود نداشته باشد، دستگاه باید خطای HTTP 400 را برگرداند.
4.4. /privet/accesstoken API
/privet/accesstoken API اختیاری است. این یک درخواست HTTP GET است. /privet/accesstoken API باید هدر معتبر "X-Privet-Token" را بررسی کند. دستگاه باید این API را در url "/privet/accesstoken" پیاده سازی کند:GET /privet/accesstoken HTTP/1.1
هنگامی که دستگاه تماس API /accesstoken را دریافت می کند، باید با سرور تماس بگیرد تا رمز دسترسی کاربر داده شده را بازیابی کند و رمز را به مشتری بازگرداند. سپس مشتری از رمز دسترسی برای دسترسی به این دستگاه از طریق ابر استفاده می کند.
دستگاههای Cloud Print باید با API زیر تماس بگیرند:
/cloudprint/proximitytokenو پارامتر "printerid=<printer_id>" و "user" را از API محلی عبور دهید. در صورت موفقیت آمیز بودن، پاسخ سرور حاوی شی زیر خواهد بود:
"proximity_token": { "user": "user@domain.com", "token": "AAA111222333444555666777", "expires_in": 600 }دستگاه های Cloud Print باید مقدار شی "proximity_token" را در پاسخ به تماس های API /privet/accesstoken محلی ارسال کنند. اگر دستگاه بتواند تمام پارامترها (از جمله مواردی که در این مشخصات توضیح داده نشده است) را پاس کند، سودمندتر است (ضدآینده).
4.4.1. ورودی
/privet/accesstoken API دارای پارامترهای ورودی زیر است:نام | ارزش |
---|---|
کاربر | ایمیل کاربری که قصد استفاده از این نشانه دسترسی را داشت. ممکن است در درخواست خالی باشد. |
4.4.2. برگشت
/privet/accesstoken API داده های زیر را برمی گرداند:نام ارزش | نوع ارزش | شرح |
---|---|---|
نشانه | رشته | رمز دسترسی که توسط سرور برگردانده شده است |
کاربر | رشته | همان کاربر در پارامتر ورودی. |
expires_in | بین المللی | تعداد ثانیه تا انقضای این نشانه. از سرور دریافت و در این پاسخ ارسال شد. |
مثال:
{ "token": "AAA111222333444555666777", "user": "user@domain.com", "expires_in": 600 }
4.4.3. خطاها
/privet/accesstoken API ممکن است خطاهای زیر را برگرداند (برای جزئیات به بخش خطاها مراجعه کنید):خطا | شرح |
---|---|
آفلاین | دستگاه در حال حاضر آفلاین است و نمی تواند با سرور صحبت کند. |
دسترسی_رد شده | حقوق ناکافی دسترسی رد شد. وقتی سرور به صراحت درخواست را رد کرد، دستگاه باید این خطا را برگرداند. |
invalid_params | پارامترهای نامعتبر مشخص شده در درخواست. (پارامترهای ناشناخته باید با خیال راحت برای سازگاری در آینده نادیده گرفته شوند). برای مثال، اگر کلاینت /accesstoken?user= یا /accesstoken را صدا کند. |
خطای سرور | خطای سرور. |
invalid_x_privet_token | X-Privet-Token در درخواست نامعتبر یا خالی است. |
اگر دستگاه API /privet/accesstoken را نمایش نمیدهد، باید خطای HTTP 404 را برگرداند. اگر هدر X-Privet-Token وجود نداشته باشد، دستگاه باید خطای HTTP 400 را برگرداند.
4.5. /privet/capabilities API
/privet/capabilities API اختیاری است. این یک درخواست HTTP GET است. /privet/capabilities API باید هدر معتبر "X-Privet-Token" را بررسی کند. دستگاه باید این API را در آدرس اینترنتی "/privet/capabilities" پیادهسازی کند:GET /privet/capabilities HTTP/1.1وقتی دستگاه تماس API /capabilities را دریافت میکند، اگر دستگاه قادر باشد، برای دریافت قابلیتهای بهروز باید با سرور تماس بگیرد. به عنوان مثال، اگر چاپگری از ارسال یک کار چاپی (دریافت محلی) برای خود از طریق سرویس Cloud Print پشتیبانی می کند، باید قابلیت هایی را که سرویس Cloud Print باز می گرداند، بازگرداند. Cloud Print در این مورد ممکن است قابلیتهای چاپگر اصلی را با افزودن ویژگیهای جدیدی که ممکن است قبل از ارسال کار به چاپگر انجام دهد، تغییر دهد. رایج ترین مورد، فهرستی از انواع اسناد پشتیبانی شده است. اگر چاپگر آفلاین است، باید انواع اسنادی را که پشتیبانی میکند بازگرداند. با این حال، اگر چاپگر آنلاین است و با Cloud Print ثبت شده است، باید "*/*" را به عنوان یکی از انواع پشتیبانی شده برگرداند. سرویس Cloud Print در این حالت تبدیل لازم را انجام خواهد داد. برای چاپ آفلاین، چاپگر باید حداقل از قالب "تصویر/pwg-raster" پشتیبانی کند.
4.5.1. ورودی
/privet/capabilities API دارای پارامترهای ورودی زیر است:نام | ارزش |
---|---|
آفلاین | (اختیاری) فقط می تواند "آفلاین=1" باشد. در این حالت، دستگاه باید قابلیتهایی را برای استفاده آفلاین بازگرداند (اگر با قابلیتهای «آنلاین» متفاوت باشد). |
4.5.2. برگشت
/privet/capabilities API قابلیتهای دستگاه را در قالب JSON توصیف دستگاه ابری (CDD) برمیگرداند (برای جزئیات به سند CDD مراجعه کنید). حداقل چاپگرها باید لیستی از انواع پشتیبانی شده را در اینجا برگردانند. به عنوان مثال، یک چاپگر Cloud Ready که در حال حاضر آنلاین است ممکن است چیزی شبیه به این را برگرداند (حداقل):{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" }, { "content_type": "*/*" } ] } }و هنگامی که از سرور جدا می شود، ممکن است برگردد:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }
توجه : چاپگرها اولویت نوع محتوای پشتیبانی شده را با استفاده از ترتیب بیان می کنند. به عنوان مثال، در نمونه های بالا، چاپگر مشخص می کند که داده های "application/pdf" را به "image/pwg-raster" و "image/jpeg" ترجیح می دهد. مشتریان باید در صورت امکان به اولویت بندی چاپگر احترام بگذارند (برای جزئیات به سند CDD مراجعه کنید).
4.5.3. خطاها
/privet/capabilities API ممکن است خطاهای زیر را برگرداند (برای جزئیات به بخش خطاها مراجعه کنید):خطا | شرح |
---|---|
invalid_x_privet_token | X-Privet-Token در درخواست نامعتبر یا خالی است. |
اگر دستگاه API /privet/capabilities را نمایش نمیدهد، باید خطای HTTP 404 را برگرداند. اگر هدر X-Privet-Token وجود نداشته باشد، دستگاه باید خطای HTTP 400 را برگرداند.
4.6. خطاها
خطاها از APIهای بالا در قالب زیر بازگردانده می شوند:نام ارزش | نوع ارزش | شرح |
---|---|---|
خطا | رشته | نوع خطا (تعریف شده برای API) |
شرح | رشته (اختیاری) | توصیف خطا توسط انسان. |
server_api | رشته (اختیاری) | در صورت خطای سرور، این فیلد حاوی API سرور است که ناموفق است. |
سرور_کد | int (اختیاری) | در صورت خطای سرور، این فیلد حاوی کد خطایی است که سرور برگردانده است. |
سرور_http_code | int (اختیاری) | در صورت بروز خطای HTTP سرور، این قسمت حاوی کد خطای HTTP است که سرور برگردانده شده است. |
تایم اوت | int (اختیاری) | تعداد ثانیههایی که مشتری باید قبل از امتحان مجدد منتظر بماند (فقط برای خطاهای قابل بازیابی). مشتری باید وقفه زمانی واقعی را از این مقدار به مقدار 20% به صورت تصادفی تبدیل کند. |
اگر هدر X-Privet-Token وجود نداشته باشد، همه APIها باید خطای HTTP 400 را برگردانند.
سرصفحه HTTP/1.1 400 X-Privet-Token وجود ندارد.
مثال 1:
{ "error": "server_error", "description": "Service unavailable", "server_api": "/submit", "server_http_code": 503 }
مثال 2:
{ "error": "printer_busy", "description": "Printer is currently printing other job", "timeout": 15 }
5. API چاپگر
یکی از انواع دستگاه هایی که این پروتکل پشتیبانی می کند چاپگر نوع است. دستگاههایی که از این نوع پشتیبانی میکنند، ممکن است برخی از عملکردهای خاص چاپگرها را اجرا کنند. در حالت ایدهآل، چاپ روی چاپگرهای آماده ابری از طریق سرور Cloud Print انجام میشود:
در برخی موارد ممکن است مشتری نیاز به ارسال سند به صورت محلی داشته باشد. ممکن است زمانی که مشتری شناسه Google نداشته باشد یا نتواند با سرور Cloud Print صحبت کند، نیاز باشد. در این صورت، کار چاپ به صورت محلی به چاپگر ارسال می شود. چاپگر به نوبه خود از سرویس Cloud Print برای صف بندی کار و تبدیل استفاده می کند. چاپگر کار ارسال شده به صورت محلی را مجدداً به سرویس Cloud Print ارسال می کند و سپس آن را درخواست می کند، زیرا از طریق ابر ارسال شده است. این فرآیند تجربه کاربری انعطاف پذیری را از نظر خدمات (تبدیل) و مدیریت/ردیابی کار چاپ ارائه می دهد.
از آنجایی که سرویس Cloud Print تبدیل را اجرا می کند، چاپگر باید از همه فرمت های ورودی ("*/*") در میان لیست انواع محتوای پشتیبانی شده، تبلیغ کند:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "*/*" } ] } }
در برخی موارد یک راه حل کاملا آفلاین مورد نظر است. از آنجایی که چاپگرها از تعداد محدودی از فرمتهای ورودی پشتیبانی میکنند، مشتری باید اسناد را به چند فرمت چاپگر پشتیبانی شده بومی تبدیل کند.
این مشخصات به همه چاپگرها نیاز دارد که حداقل از قالب PWG Raster ("تصویر/pwg-raster") برای جعبه چاپ آفلاین پشتیبانی کنند. چاپگر ممکن است از فرمت های دیگری (به عنوان مثال JPEG) پشتیبانی کند و اگر مشتری از آن پشتیبانی کند، ممکن است اسناد را در آن قالب ارسال کند. چاپگر باید انواع پشتیبانی شده را از طریق /capabilities API نمایش دهد، برای مثال:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }دو راه وجود دارد که مشتری می تواند چاپ را از طریق شبکه محلی آغاز کند.
چاپ ساده - مشتری سند را از طریق شبکه محلی به /submitdoc API می فرستد (بدون تعیین پارامتر job_id). سند ارسالی با استفاده از تنظیمات پیشفرض بلیط چاپ چاپ میشود و نیازی به وضعیت کار چاپ نیست. اگر چاپگر فقط از این نوع چاپ پشتیبانی می کند، باید ONLY /submitdoc API را در پاسخ API /privet/info تبلیغ کند.
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
چاپ پیشرفته - مشتری باید ابتدا با فراخوانی /privet/printer/createjob API با یک بلیط کار معتبر CJT در درخواست، یک کار چاپ روی چاپگر ایجاد کند. چاپگر باید بلیط چاپ را در حافظه ذخیره کند و یک job_id را به مشتری برگرداند. سپس مشتری /printer/submitdoc API را فراخوانی می کند و job_id قبلاً دریافت شده را مشخص می کند. در آن زمان چاپگر شروع به چاپ می کند. مشتری با فراخوانی /privet/printer/jobstate API وضعیت کار چاپ را از چاپگر نظرسنجی می کند.
در یک محیط چند مشتری، هیچ تضمینی وجود ندارد که این API چگونه نامیده شود. این امکان برای یک کلاینت وجود دارد که بین تماس های / createjob->/submitdoc مشتری دیگر /createjob را فراخوانی کند. برای حذف بن بست های احتمالی و بهبود قابلیت استفاده، توصیه می کنیم یک صف کوچک از کارهای چاپی در انتظار چاپگر داشته باشید (حداقل 3-5):
- /createjob اولین نقطه موجود در صف را می گیرد.
- طول عمر کار (در صف) حداقل 5 دقیقه است.
- اگر تمام نقاط صف گرفته شود، قدیمیترین کار غیرچاپ حذف شده و کار جدید در آنجا قرار میگیرد.
- If there is a print job currently printing on the device (simple or advanced printing), /submitdoc should return status busy and propose a timeout to retry this print job.
- If /submitdoc refers to a job that has been removed from the queue (due to replacement or timeout), the printer should return an error invalid_print_job and the client will retry the process from the /createjob step. The client MUST wait for a random timeout period of up to 5 seconds before retrying.
If memory constraints prevent storing multiple pending jobs on the device, it is possible to have a queue of 1 print job long. It should still follow the same protocol as above. After a job has completed or failed with an error, the printer should store information about the job's status for at least 5 minutes. The queue size for storing completed job statuses should be at least 10. If there are more job statuses that need to be stored, the oldest one may be removed from the queue before the 5 minute timeout.
Note: For now clients will poll for job status. In the future, we may require the printer to send TXT DNS notification when ANY print job status has changed.
5.1. /privet/printer/createjob API
/privet/printer/createjob API is OPTIONAL (see Simple Printing above). It is an HTTP POST request. /privet/printer/createjob API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/createjob" url:
POST /privet/printer/createjob HTTP/1.1When receiving /privet/printer/createjob API call, the printer MUST create a new print job ID, store the received print ticket in the CJT format, and return print job id back to the client.
5.1.1. Input
/privet/printer/createjob API has no input parameters in URL. The request body should contain the print job ticket data in CJT format.5.1.2. برگشت
/privet/printer/createjob API returns the following data:Value name | Value type | شرح |
---|---|---|
job_id | string | ID of the newly created print job. |
expires_in | int | Number of seconds this print job is valid. |
Example:
{ "job_id": "123", "expires_in": 600 }
5.1.3. Errors
/privet/printer/createjob API may return the following errors (see Errors section for details):Error | شرح |
---|---|
invalid_ticket | Submitted print ticket is invalid. |
printer_busy | Printer is busy and can't currently process /createjob. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/createjob it MUST return HTTP 404 error. If X-Privet-Token header is missing, the device MUST return HTTP 400 error.
5.2. /privet/printer/submitdoc API
/privet/printer/submitdoc API is REQUIRED to implement printing over a local network (offline or repost to Cloud Print). It is an HTTP POST request. /privet/printer/submitdoc API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/submitdoc" url:POST /privet/printer/submitdoc HTTP/1.1When receiving the /privet/printer/submitdoc API call, the printer should start printing. If it is unable to begin printing, it MUST return the error printer_busy and a recommended timeout period for the client to wait before trying again.
If the printer is not able to hold all of the data in its internal buffer, it SHOULD use TCP mechanisms to slow down data transfer until it prints a portion of the document, making part of the buffer available again. (For example, the printer may set windowsize=0 on TCP layers, which will make the client wait.)
Submitting a document to the printer may take a significant amount of time. The client should be able to check the state of the printer and job (advanced printing) while printing is in progress. In order to do that, the printer MUST allow the client to call the /privet/info and /privet/printer/jobstate APIs while processing /privet/printer/submitdoc API calls. It is recommended for all clients to start a new thread to execute the /privet/printer/submitdoc API call, so that the main thread can use the /privet/info and /privet/printer/jobstate APIs to check printer and job states.
Note : Upon completion or abortion of the local print job, it is strongly recommended (and will be required in a future version of this spec) to report the final state of the job to the /cloudprint/submit interface for accounting and user experience purposes. The parameters "printerid", "title", "contentType" and "final_semantic_state" (in PrintJobState format) are required, and the parameters "tag" (repeated parameter) and "ticket" (the ticket of the job in CloudJobTicket format). Note that the provided PrintJobState must actually be final, ie its type must be DONE or ABORTED, and a cause must be provided in the case that it is ABORTED (see JobState for details). Also note that this use of the /cloudprint/submit interface to report local print jobs is not mentioned in its specification because that section is intended to describe the interface's primary use: submitting a print job with the document to print provided in the "content" parameter.
5.2.1. Input
/privet/printer/submitdoc API has the following input parameters:نام | Value |
---|---|
job_id | (optional) Print job id. May be omitted for simple printing case (see above). Must match the one returned by the printer. |
user_name | (optional) Human readable user name. This is not definitive, and should only be used for print job annotations. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
client_name | (optional) Name of the client application making this request. For display purposes only. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
job_name | (optional) Name of the print job to be recorded. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
offline | (optional) Could only be "offline=1". In this case printer should only try printing offline (no re-post to Cloud Print server). |
Request body should contain a valid document for printing. "Content-Length" should include the correct length of the request. "Content-Type" header should be set to document MIME type and match one of the types in the CDD (unless CDD specifies "*/*").
Clients are HIGHLY recommended to provide a valid user name (or email), a client name and a job name with this request. Those fields are only used in UIs to improve user experience.
5.2.2. برگشت
/privet/printer/submitdoc API returns following data:Value name | Value type | شرح |
---|---|---|
job_id | string | ID of the newly created print job (simple printing) or job_id specified in the request (advanced printing). |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | Content-type of the submitted document. |
job_size | int 64 bit | Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
Example:
{ "job_id": "123", "expires_in": 500, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
5.2.3. Errors
/privet/printer/submitdoc API may return the following errors (see Errors section for details):Error | شرح |
---|---|
invalid_print_job | Invalid/expired job id is specified in the request. Retry after timeout. |
invalid_document_type | Document MIME-type is not supported by the printer. |
invalid_document | Submitted document is invalid. |
document_too_large | Document exceeds maximum size allowed. |
printer_busy | Printer is busy and can't currently process document. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility) |
user_cancel | User explicitly cancelled printing process from the device. |
server_error | Posting document to Cloud Print has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If the device is not exposing /privet/printer/submitdoc, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
Note : /privet/printer/submitdoc API may require special handling on printer side (because of the large payload attached). In some cases (depends on the printer HTTP server implementation and platform), printer may close socket BEFORE returning HTTP error. In other, printer may return 503 error (instead of Privet error). Printers SHOULD try as much as possible to return Privet. However, every client implementing Privet specification SHOULD be able to handle socket close (no HTTP error) and 503 HTTP error cases for /privet/printer/submitdoc API. In this case, client SHOULD handle it as a Privet "printer_busy" error with "timeout" set to 15 seconds. To avoid infinite retries, client may stop retrying after a reasonable number of attempts (for example, 3).
5.3. /privet/printer/jobstate API
/privet/printer/jobstate API is OPTIONAL (see Simple Printing above). It is an HTTP GET request. /privet/printer/jobstate API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/jobstate" url:GET /privet/printer/jobstate HTTP/1.1When receiving a /privet/printer/jobstate API call, a printer should return the status of the requested print job or invalid_print_job error.
5.3.1. Input
/privet/printer/jobstate API has following input parameters:نام | Value |
---|---|
job_id | Print job ID to return status for. |
5.3.2. برگشت
/privet/printer/jobstate API returns the following data:Value name | Value type | شرح |
---|---|---|
job_id | string | Print job id there status information is for. |
state | string | draft - print job has been created on the device (no /privet/printer/submitdoc calls have been received yet). queued - print job has been received and queued, but printing has not started yet. in_progress - print job is in the progress of printing. stopped - print job has been paused, but can be restarted manually or automatically. done - print job is done. aborted - print job failed. |
description | string | (optional) Human readable description of the print job status. Should include additional information if state < is stopped or aborted . The semantic_state field usually provides better and more meaningful description to the client. |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | (optional) Content-type of the submitted document. |
job_size | int 64 bit | (optional) Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
server_job_id | string | (optional) ID of the job returned from the server (if job has been posted to Cloud Print service). Omitted for offline printing. |
semantic_state | JSON | (optional) Semantic state of the job in PrintJobState format. |
Example (printing by reporting through Cloud Print):
{ "job_id": "123", "state": "in_progress", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "server_job_id": "1111-2222-3333-4444" }
Example (offline printing error):
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
Example (print job aborted by the user):
{ "job_id": "123", "state": "aborted", "description": "User action", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "ABORTED", "user_action_cause": {"action_code": "CANCELLED"} }, "pages_printed": 7 } }
Example (print job stopped due to out of paper). Notice the reference to the device state. The client will need to call the /privet/info API to get more details about the device state:
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": "123456", "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "STOPPED", "device_state_cause": {"error_code": "INPUT_TRAY"} }, "pages_printed": 7 } }
5.3.3. Errors
/privet/printer/jobstate API may return the following errors (see Errors section for details):Error | شرح |
---|---|
invalid_print_job | Invalid/expired job ID is specified in the request. |
server_error | Getting print job status (for print jobs posted to Cloud Print) has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/jobstate, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
6. Appendix
6.1. Default behavior and settings
This section will explain the default behavior we expect from ALL Privet-compatible devices.- Out-of-the-box devices should support only /privet/info and /privet/register APIs. All other APIs (eg /privet/accesstoken, local printing) should be disabled.
- Registration requires physical interaction with a device.
- User MUST take a physical action on the device (eg, pressing a button) to confirm their access to the device.
- After the user takes the action noted above, the printer should send the /cloudprint/register request. It should not send this request until after the action is taken (see Sequence Diagram 1).
- If the device is processing a /privet/register request (for instance, waiting on the action above), it must reject all other /privet/register requests. The device MUST return the device_busy error in this case.
- The device should timeout any /register request that does not receive the physical action mentioned above within 60 seconds. The device MUST return the confirmation_timeout error in this case.
- Optional: Recommended but not required, the following may improve user experience:
- The printer might flash a light or its screen to indicate that the user needs to take an action to confirm registration.
- The printer might state on its screen that 'it is being registered to Google Cloud Print for user ' abc@def.com ' - press OK to continue', where abc@def.com is the user parameter from the /register API call. This would make it clearer to a user that:
- it is their registration request that they are confirming
- what is happening if s/he didn't trigger the request.
- In addition to a physical action to confirm from the printer (eg, 'Press the OK button'), a printer may also offer the user a button to cancel the request (eg, 'Press Cancel to reject'). This would allow users who did not trigger the registration request to cancel it before the 60 second timeout. The device MUST return the user_cancel error in this case.
- Ownership transfers:
- The device may be deleted explicitly from the Cloud service.
- If the device receives success, but no device description as a result of /cloudprint/printer (for GCP) call, it MUST revert to default (out-of-the-box) mode.
- If the device's credentials no longer work (explicitly because of "invalid credentials" response from the server), it MUST revert to default (out-of-the-box) mode.
- Local factory reset MUST clear device's credentials and set it to default state.
- Optional: The device may provide a menu item to clear credentials and put it into default mode.
- Devices supporting XMPP notifications MUST include the ability to ping the server. The ping timeout MUST be controllable from the server through "local_settings".
- The device may explicitly ping the server (/cloudprint/printer API for GCP, in addition to XMPP pings) no more often than once a day (24 hours) to make sure they are in sync. It is recommended to randomize the check window within 24-32 hour window.
- Optional: For Cloud Print devices, it is recommended but not required to have a manual way (button) to allow the user to initiate a check for new print jobs from the device. Some printers already have this.
- Optional. Enterprise printers may have an option to disable local discovery completely. In such case, the device MUST update these local settings on the server. New local settings MUST be empty (setting "local_discovery" to "false", means that it can be re-enabled from the GCP Service).
6.1.2 Default Registration Diagram
6.2. XSSI and XSRF attacks and prevention
This section will explain the possibility of XSSI and XSRF attacks on the device and how to protect from them (including token generation techniques).More details are here: http://googleonlinesecurity.blogspot.com/2011/05/website-security-for-webmasters.html
Normally, XSSI and XSRF attacks are possible when a site is using cookie authentication mechanisms. While Google doesn't use cookies with their Cloud Print Service, such attacks are still possible. Local network access, by design, implicitly trusts requests.
6.2.1. XSSI
It is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and to try to call the Privet API using "src=<api name>" inside of a <script> tag:<script type="text/javascript" src="http://192.168.1.42:8080/privet/info"></script>Without protection, malicious websites would be able to execute API calls and access results.
To prevent this type of attack, ALL Privet API calls MUST require the "X-Privet-Token" header in the request. "src=<api>" script tags are not able to add headers, effectively guarding against this type of attack.
6.2.2. XSRF
http://en.wikipedia.org/wiki/Cross-site_request_forgeryIt is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and try to call Privet API using an <iframe>, forms, or some other cross-website loading mechanism. Attackers would not be able to access the results of the request, but if the request would perform an action (eg printing), they could trigger it.
To prevent this attack, we require the following protection:
- Leave /privet/info API open to XSRF
- /privet/info API MUST NOT perform any actions on the device
- Use /privet/info API to receive x-privet-token
- All other APIs MUST check for a valid x-privet-token in "X-Privet-Token" header.
- x-privet-token SHOULD be valid for only 24 hours.
Even if an attacker is able to execute the /privet/info API, they would not be able to read x-privet-token from the response and therefore would not be able to call any other API.
It is strongly recommended to generate the XSRF token using the following algorithm:
XSRF_token = base64( SHA1(device_secret + DELIMITER + issue_timecounter) + DELIMITER + issue_timecounter )
XSRF Token Generation Elements:
- DELIMITER is a special character, usually ':'
- issue_timecounter is a number of seconds since some event (epoch for timestamp) or device boot time (for CPU counters). issue_timecounter is constantly increasing when the device is up and running (see token verification below).
- SHA1 - hash function using SHA1 algorithm
- base64 - base64 encoding
- device_secret - secret specific to the device. Device secret MUST be updated on every restart.
Recommended ways to generate device secret:
- Generate a new UUID on every restart
- Generate a 64 bit random number on every restart
The device is not required to store all of the XSRF tokens it has issued. When the device needs to verify a XSRF token for validity, it should base64-decode the token. Get the issue_timecounter from the second half (cleartext), and try to produce SHA1 hash of device_secret + DELIMITER + issue_timecounter where issue_timecounter is from the token. If the newly generated SHA1 matches the one in the token, device must now check if the issue_timecounter is within the validity period from (24 hours) of the current time counter. To do so, device takes the current time counter (CPU counter for example) and subtracts issue_timecounter from it. The result MUST be the number of seconds since token issue.
Important: This is the recommended way to implement XSRF protection. Clients of the Privet specification shall not try to understand XSRF token, instead they shall treat is as a blackbox. Figure 6.2.3 illustrates a recommended way to implement the X-Privet-Token and verification of a typical request.
6.2.3 X-Privet Token Generation and Verification Sequence Diagram
6.3. Workflow diagrams
This section will illustrate a workflow in different cases.6.3.1. Printer out of the box workflow
6.3.2. Registered printer startup
6.3.3 XMPP notifications handling workflow
6.3.4. Check printer settings workflow
،Privet is a Cloud Device Local Discovery API used by cloud services. This document is organized into the following sections:
- Introduction : introduction to Privet
- Discovery : local discovery mechanisms
- Announcements : local discovery announcements
- API : Privet APIs for general cloud devices
- Printer API : Privet APIs used by printers
- Appendix : supplemental diagrams
1. Introduction
Cloud connected devices have many benefits. They can use online conversion services, host job queues while the device is offline, and be accessible from anywhere in the world. However, with many cloud devices accessible by a given user, we need to provide a method for finding the nearest device based on location. The purpose of the Privet protocol is to bind the flexibility of cloud devices with a suitable local discovery mechanism so that devices are easily discovered in new environments.
The goals of this protocol are:- make cloud devices locally discoverable
- register cloud devices with a cloud service
- associate registered devices with their cloud representation
- enable offline functionality
- simplify implementation so that small devices can utilize it
The Privet protocol consists of 2 main parts: discovery and API. Discovery is used to find the device on the local network, and the API is used to get information about the device and perform some actions. Throughout this document, the device refers to a cloud connected device implementing the Privet protocol.
2. Discovery
Discovery is a zeroconf based (mDNS + DNS-SD) protocol. The device MUST implement IPv4 Link-Local Addressing. The device MUST comply with the mDNS and DNS-SD specs.
- http://www.rfc-editor.org/rfc/rfc3927.txt (IPv4 Link-local)
- http://www.rfc-editor.org/rfc/rfc4862.txt (IPv6 Link-local)
- http://www.rfc-editor.org/rfc/rfc6762.txt (mDNS)
- http://www.rfc-editor.org/rfc/rfc6763.txt (DNS-SD)
The device MUST perform name conflict resolution according to the above specifications.
2.1. Service Type
DNS Service Discovery uses the following format for service types: _applicationprotocol._transportprotocol . In the case of the Privet protocol, the service type for DNS-SD should be: _privet._tcp
The device can implement other service types as well. It is advised to use the same service instance name for all service types implemented by the device. For example: a printer may implement "Printer XYZ._privet._tcp" and "Printer XYZ._printer._tcp" services. It will simplify setup for the user. However, Privet clients will look only for "_privet._tcp".
In addition to the main service type, the device MUST advertise the PTR records for its corresponding subtype(s) (see DNS-SD spec: "7.1. Selective Instance Enumeration (Subtypes)"). Format should be following: _<subtype>._sub._privet._tcp
Currently the only device subtype supported is printer . So, all printers MUST advertise two PTR records:
- _privet._tcp.local.
- _printer._sub._privet._tcp.local.
2.2. TXT record
The DNS Service Discovery defines fields to add optional information about a service in the TXT records. A TXT record consists of key/value pairs. Each key/value pair starts from the length byte followed by up to 255 bytes of text. The key is the text before the first '=' character and the value is the text after the first '=' character until the end. The specification allows for no value in the record, in such case the will be no '=' character OR no text after the '=' character. (See DNS-SD spec: "6.1. General Format Rules for DNS TXT Records" for the DNS TXT record format and "6.2. DNS-SD TXT Record Size" for the recommended length).
Privet requires the device to send the following key/value pairs in the TXT record. Key/Value strings are case-insensitive, for example "CS=online" and "cs=ONLINE" are the same. Information in the TXT record MUST be the same as accessible through /info API (see 4.1. API section).
It is recommended to keep TXT record size under 512 bytes.
2.2.1. txtvers
Version of the TXT structure. txtvers MUST be the first record of the TXT structure. Currently the only supported version is 1.
txtvers=1
2.2.2. ty
Provides a user-readable name of the device. For example:
ty=Google Cloud Ready Printer Model XYZ
2.2.3. note (optional)
Provides a user-readable name of the device. For example:
note=1st floor lobby printer
Note: This is an optional key and may be skipped. However, if present, user SHOULD be able to modify this value. The same description MUST be used when registering device.
2.2.4. url
Server URL this device is connected to (including protocol). For example:
url=https://www.google.com/cloudprint
2.2.5. type
Comma-separated list of device subtypes supported by this device. Format is: "type=_subtype1,_subtype2". Currently, the only supported device subtype is printer .
type=printer
Each subtype listed should be advertised using a corresponding PTR record. For each supported service subtype, there should be one corresponding item. Service subtype name (<subtype>._sub._privet._tcp) should be equal to device type here.
2.2.6. id
Device ID. If the device has not been registered yet, this key should be present, but value should be empty. For example:
id=11111111-2222-3333-4444-555555555555 id=
2.2.7. cs
Indicates the device's current connection state. Four possible values are defined in this spec.
- "online" indicates that the device is currently connected to the cloud.
- "offline" indicates that the device is available on the local network, but can't talk to the server.
- "connecting" indicates that the device is performing its startup sequence and is not fully online yet.
- "not-configured" indicates that the device's internet access has not been configured yet. This value is not currently used, but may be useful in future versions of the specification.
- cs=online
- cs=offline
- cs=connecting
If the device has been registered with a cloud, on startup it should check connectivity with a server to detect its connection state (for example, calling cloud API to get device settings). The device may use its notifications channel (eg XMPP) connection state to report this value. Unregistered devices on startup may ping a domain in order to detect their connection state (for example, ping www.google.com for cloud print devices).
3. Announcements
On device startup, shutdown or state change, the device MUST perform the announcement step as described in the mDNS specification. It SHOULD send the corresponding announcement at least twice with at least a one-second interval between them.
3.1. Startup
On device startup it MUST perform probing and announcing steps as described in the mDNS specification. SRV, PTR and TXT records should be sent in this case. It is recommended to group all records into one DNS response if possible. If not, the following order is recommended: SRV, PTR, TXT records.
3.2. Shutdown
On device shutdown it SHOULD try to notify all interested parties about it by sending a "goodbye packet" with TTL=0 (as described in mDNS documentation).
3.3. Update
In case of any information described in TXT has changed, the device MUST send an update announcement. It is enough to only send the new TXT record in this case. For example, after a device is registered, it MUST send an update announcement including the new device id.
4. API
After a cloud device has been discovered, client communication is enabled with the device directly over the local network. All APIs are HTTP 1.1 based. Data formats are JSON based. API requests may be GET or POST requests.
Each request MUST contain a valid " X-Privet-Token " header. The ONLY request allowed to have an empty "X-Privet-Token" header is the /privet/info request (note that the header MUST still be present). If the "X-Privet-Token" header is missing, the device MUST respond with the following HTTP 400 error:
HTTP/1.1 400 Missing X-Privet-Token header.
If "X-Privet-Token" header is empty or invalid, the device MUST respond with "invalid X-Privet-Token error" (invalid_x_privet_token, see Errors section for details). The only exception is the /info API. To see more info on why this is done and how tokens should be generated, see Appendix A: XSSI and XSRF attacks and prevention.
If a requested API does not exist or is not supported, the device MUST return an HTTP 404 error.
4.1. API availability
Before ANY API is exposed (including the /info API), the device MUST contact the server to check local settings . Local settings MUST be preserved between restarts. If the server is not available, the last known local settings should be used. If the device has not been registered yet, it should follow the default settings.
Cloud Print devices MUST follow the steps below to register, receive and update local settings.
4.1.1. Registration
When the device registers, it MUST specify the "local_settings" parameter, as follows:
{ "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 } }The following settings can be set:
Value Name | Value Type | شرح |
---|---|---|
local_discovery | boolean | Indicates if local discovery functionality is allowed. If "false", all local API (including /info) and DNS-SD discovery must be disabled. By default, newly registering devices should pass "true". |
access_token_enabled | boolean (optional) | Indicates if /accesstoken API should be exposed on the local network. By default should be "true". |
printer/local_printing_enabled | boolean (optional) | Indicates if local printing functionality (/printer/createjob, /printer/submitdoc, /printer/jobstate) should be exposed on the local network. By default should be "true". |
printer/conversion_printing_enabled | boolean (optional) | Indicates if local printing may send job to server for conversion. Only makes sense when local printing is enabled. |
xmpp_timeout_value | int (optional) | Indicates the number of seconds between XMPP channel pings. By default MUST be 300 (5 minutes) or more. |
Important: The lack of any optional value indicates that the corresponding functionality is completely unsupported by the device.
4.1.2. Startup
On device startup, it should contact the server to check what APIs are available to be exposed in the local network. For printers connected to Cloud Print, they should call:
/cloudprint/printer?printerid=<printer_id>or
/cloudprint/list
/cloudprint/printer is preferred over /cloudprint/list, but both will work.
This API returns current device parameters, including settings for local API. The reply from the server will have the following format:
"local_settings": { "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 }, "pending": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": false, "printer/conversion_printing_enabled": false, "xmpp_timeout_value": 500 } }
"current" object indicates settings that are in effect at the moment.
"pending" object indicates settings that should be applied to the device (this object may be missing).
Once the device sees "pending" settings, it MUST update its state (see below).
4.1.3. Update
If settings update is needed, an XMPP notification will be sent to the device. The notification will be in the following format:
<device_id>/update_settings
On receiving such a notification, the device MUST query the server to get the latest settings. Cloud Print devices MUST use:
/cloudprint/printer?printerid=<printer_id>
Once the device sees "pending" section as a result of the /cloudprint/printer API (at startup or due to the notification), it MUST update its internal state to remember the new settings. It MUST call the server API to confirm the new settings. For Cloud Printers, the device MUST call /cloudprint/update API and use "local_settings" parameter as during registration.
When re-connecting to XMPP channel, the device MUST call /cloudprint/printer API to check if local settings has been changed since the last time.
4.1.3.1. Local Settings Pending
"local_settings" parameter that device uses to call server API MUST NEVER contain "pending" section.
4.1.3.2. Local Settings Current
ONLY the device can change the "current" section of the "local_settings". Everybody else will change the "pending" section, and wait until changes get propagated to the "current" section by the device.
4.1.4. Offline
When unable to contact the server during startup, after notification, device MUST use last known local settings.
4.1.5. Deleting device from the service
If the device has been deleted from the service (GCP for example), an XMPP notification will be sent to the device. The notification will be in the following format:
<device_id>/delete
On receiving such a notification, the device MUST go to the server to check its state. Cloud Print devices MUST use:
/cloudprint/printer?printerid=<printer_id>
The device MUST receive a successful HTTP answer with success=false and no device/printer description. It means device has been removed from the server, and the device MUST erase its credentials and go to default factory settings mode.
ANY time the device receives a reply indicating it has been deleted as a result of the /cloudprint/printer API (startup, update settings notification, daily ping), it MUST delete its credentials and go to default mode.
4.2. /privet/info API
The info API is MANDATORY and MUST be implemented by every device. It is an HTTP GET request for "/privet/info" url: GET /privet/info HTTP/1.1
The info API returns basic information about a device and functionality it supports. This API MUST never change the device status or perform any action, since it is vulnerable to XSRF attacks. This is the ONLY API allowed to have an empty "X-Privet-Token" header. Clients should call /privet/info API with "X-Privet-Token" header set to X-Privet-Token: ""
The info API MUST return data consistent with data available in the TXT record during discovery.
4.2.1. Input
/privet/info API has no input parameters.
4.2.2. برگشت
/privet/info API returns basic information about device and supported functionality.
The TXT column indicates the corresponding field in the DNS-SD TXT record.
Value Name | Value Type | شرح | TXT |
---|---|---|---|
version | string | Highest version (major.minor) of API supported, currently 1.0 | |
name | string | Human readable name of the device. | ty |
description | string | (optional) Device description. SHOULD be modifiable by user. | note |
url | string | URL of the server this device is talking to. URL MUST include protocol specification, for example: https://www.google.com/cloudprint. | url |
type | list of strings | List of device types supported. | type |
id | string | Device id, empty if device has not been registered yet. | id |
device_state | string | State of the device. idle means device is ready processing means device is busy and functionality may be limited for some time stopped means device is not working and user intervention is required | |
connection_state | string | State of the connection to the server (base_url) online - connection available offline - no connection connecting - performing startup steps not-configured - connection has not been configured yet A registered device may report its connection state based on the state of the notification channel (eg XMPP connection state). | cs |
manufacturer | string | Name of the device manufacturer | |
model | string | Model of the device | |
serial_number | string | Unique device identifier. In this spec, this MUST be a UUID. (GCP 1.1 spec) (optional) We strongly recommend using the same serial number ID everywhere, so different clients can identify the same device. For example, printers implementing IPP may use this serial number ID in "printer-device-id" field. | |
firmware | string | Device firmware version | |
uptime | int | Number of seconds from the device boot. | |
setup_url | string | (optional) URL (including protocol) of the page with setup instructions | |
support_url | string | (optional) URL (including protocol) of the page with support, FAQ information | |
update_url | string | (optional) URL (including protocol) of the page with update firmware instructions | |
x-privet-token | string | Value of the X-Privet-Token header that has to be passed to all APIs to prevent XSSI and XSRF attacks. See 6.1. for details. | |
api | description of APIs | List of supported APIs (described below) | |
semantic_state | JSON | (optional) Semantic state of the device in CloudDeviceState format. |
api - is a JSON list containing the list of APIs available through the local network. Note that not all APIs may be available at the same time over the local network. For example, a newly connected device should only support the /register api:
"api": [ "/privet/register", ]Once device registration is complete, the device SHOULD stop supporting the /register API. The device should also check with the service to provide what APIs can be exposed over the local network. For example:
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
The following APIs are available at this time:
- /privet/register - API for device registration over the local network. (see /privet/register API for details). This API MUST be hidden once the device is successfully registered in the cloud.
- /privet/accesstoken - API to request access token from the device (see /privet/accesstoken API for details).
- /privet/capabilities - API to retrieve device capabilities (see /privet/capabilities API for details).
- /privet/printer/* - API specific to the device type "printer", see printer specific APIs for details.
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "idle", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ] }Here is an example of the /privet/info response for a printer that ran out of ink (notice semantic_state field):
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "stopped", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ], "semantic_state": { "version": "1.0", "printer": { "state": "STOPPED", "marker_state": { "item": [ { "vendor_id": "ink", "state": "EXHAUSTED", "level_percent": 0 } ] } } } }
4.2.3. Errors
/privet/info API should ONLY return an error if X-Privet-Token header is missing. It MUST be HTTP 400 error:
HTTP/1.1 400 Missing X-Privet-Token header.
4.3. /privet/register API
/privet/register API is OPTIONAL. It is an HTTP POST request. /privet/register API MUST check for a valid X-Privet-Token header. Device MUST implement this API on "/privet/register" url:
POST /privet/register?action=start&user=user@domain.com HTTP/1.1 POST /privet/register?action=complete&user=user@domain.com HTTP/1.1
The device should expose /privet/register API ONLY when it allows anonymous registration at the moment. For example:
- When the device is turned on (or after clicking a special button on the device) and has not been registered yet, it should expose the /privet/register API to allow a user from the local network to claim the printer.
- After registration is complete, the device should stop exposing the /privet/register API to prevent another user on the local network from reclaiming the device.
- Some devices may have different ways to register devices and should not expose the /privet/register API at all (for example, Chrome Cloud Print connector).
The registration process consists of 3 steps (see anonymous registration for Cloud Print).
- Initiate anonymous registration process.
- A client initiates this process by calling the /privet/register API. The device may wait for user confirmation at that time.
- Get claim token.
The client polls to find out when the device is ready to continue. Once the device is ready, it sends a request to the server to retrieve registration token and registration URL. Received token and URL SHOULD be returned to the client. During this step, if the device receives another call to initialize registration, it should:
- If this is the same user who started registration - drop all previous data (if any) and start a new registration process.
- If this is different user - return device_busy error and 30 seconds timeout.
Complete registration process.
After the client has claimed the device, the client should notify the device to complete registration. Once the registration process is complete, the device should send an update announcement, including the newly acquired device id.
Note: When the device is processing a /privet/register API call, no other /privet/register API calls may be processed simultaneously. The device MUST return the device_busy error and 30 seconds timeout.
User confirmation for registration on the device is HIGHLY recommended. If implemented, the device MUST wait for user confirmation AFTER it receives a /privet/register?action=start API call. The client will be calling /privet/register?action=getClaimToken API to find out when user confirmation is complete and claim token is available. If the user cancels registration on the device (eg presses the Cancel button), the user_cancel error MUST be returned. If the user has not confirmed registration within a certain timeframe, the confirmation_timeout error MUST be returned. See defaults section for more details.
4.3.1. Input
/privet/register API has the following input parameters:نام | Value |
---|---|
action | می تواند یکی از موارد زیر باشد: start - to start registration process getClaimToken - retrieve claim token for the device cancel - to cancel registration process complete - to complete registration process |
user | Email of the user who will claim this device. |
The device MUST check that the email address from all actions (start, getClaimToken, cancel, complete) matches.
4.3.2. برگشت
/privet/register API returns following data:Value name | Value type | شرح |
---|---|---|
action | string | Same action as in input parameter. |
user | string (optional) | Same user as in input parameter (may be missing, if omitted in the input). |
token | string (optional) | Registration token (mandatory for "getClaimToken" response, omitted for "start", "complete", "cancel"). |
claim_url | string (optional) | Registration URL (mandatory for "getClaimToken" response, omitted for "start", "complete", "cancel"). For Cloud Printers it must be the "complete_invite_url" received from the server. |
automated_claim_url | string (optional) | Registration URL (mandatory for "getClaimToken" response, omitted for "start", "complete", "cancel"). For Cloud Printers it must be the "automated_invite_url" received from the server. |
device_id | string (optional) | New device id (omitted for "start" response, mandatory for "complete"). |
The device MUST return its device id in the /privet/info API response ONLY after registration is complete.
Example 1:
{ "action": "start", "user": "user@domain.com", }
Example 2:
{ "action": "getClaimToken", "user": "user@domain.com", "token": "AAA111222333444555666777", "claim_url": "https://domain.com/SoMeUrL", }
Example 3:
{ "action": "complete", "user": "user@domain.com", "device_id": "11111111-2222-3333-4444-555555555555", }
4.3.3. Errors
/privet/register API may return following errors (see Errors section for details):Error | شرح |
---|---|
device_busy | The device is busy and can't perform the requested action. Retry after timeout. |
pending_user_action | In response to "getClaimToken" this error indicates that the device is still pending user confirmation, and "getClaimToken" request should be retried after timeout. |
user_cancel | User explicitly cancelled registration process from the device. |
confirmation_timeout | User confirmation times out. |
invalid_action | Invalid action is called. For example, if client called action=complete before calling action=start and action=getClaimToken. |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility). For example, return this if the client called action=unknown or user=. |
device_config_error | Date/Time (or some other settings) is wrong on the device side. User needs to go (to device internal website) and configure device settings. |
offline | The device is currently offline and can't talk to the server. |
server_error | Server error during registration process. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
The device MUST stop exposing the /privet/register API after registration has been successfully completed. If the device is not exposing the /privet/register API, it MUST return HTTP 404 error. Therefore, if a device is already registered, calling this API MUST return 404. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
4.4. /privet/accesstoken API
/privet/accesstoken API is OPTIONAL. It is an HTTP GET request. /privet/accesstoken API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on the "/privet/accesstoken" url:GET /privet/accesstoken HTTP/1.1
When the device receives the /accesstoken API call, it should call the server to retrieve the access token for the given user and return the token to the client. The client will then use the access token to access this device through the cloud.
Cloud Print devices MUST call the following API:
/cloudprint/proximitytokenand pass "printerid=<printer_id>" and "user" parameter from the local API. If successful, the server response will contain the following object:
"proximity_token": { "user": "user@domain.com", "token": "AAA111222333444555666777", "expires_in": 600 }Cloud Print devices MUST pass the value of the "proximity_token" object in the response to local /privet/accesstoken API calls. It is more advantageous (future-proof) if the device can pass ALL parameters (including ones that are not described in this spec).
4.4.1. Input
/privet/accesstoken API has the following input parameters:نام | Value |
---|---|
user | Email of the user who intended to use this access token. May be empty in the request. |
4.4.2. برگشت
/privet/accesstoken API returns following data:Value name | Value type | شرح |
---|---|---|
token | string | Access token returned by the server |
user | string | Same user as in input parameter. |
expires_in | int | Number of seconds until this token expires. Received from the server and passed in this response. |
Example:
{ "token": "AAA111222333444555666777", "user": "user@domain.com", "expires_in": 600 }
4.4.3. Errors
/privet/accesstoken API may return the following errors (see Errors section for details):Error | شرح |
---|---|
offline | Device is currently offline and can't talk to the server. |
access_denied | Insufficient rights. Access denied. The device should return this error when the request has been explicitly denied by the server. |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility). For example, if client called /accesstoken?user= or /accesstoken. |
server_error | Server error. |
invalid_x_privet_token | X-Privet-Token is Invalid or empty in the request. |
If the device is not exposing the /privet/accesstoken API, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
4.5. /privet/capabilities API
/privet/capabilities API is OPTIONAL. It is an HTTP GET request. /privet/capabilities API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/capabilities" url:GET /privet/capabilities HTTP/1.1When the device receives /capabilities API call, if the device is able, it SHOULD contact the server to get updated capabilities. For example, if a printer supports posting a print job (received locally) to itself through the Cloud Print service, it should return capabilities that the Cloud Print service would return. Cloud Print in this case may alter the original printer capabilities by adding new features it may perform before sending job to the printer. The most common case is a list of supported document types. If the printer is offline, it should return document types it supports. However, if the printer is online and registered with Cloud Print it MUST return "*/*" as one of the supported types. The Cloud Print service will perform the necessary conversion in this case. For offline printing, the printer MUST support at least the "image/pwg-raster" format.
4.5.1. Input
/privet/capabilities API has the following input parameters:نام | Value |
---|---|
offline | (optional) Can only be "offline=1". In this case the device should return capabilities for offline use (if they are different from "online" capabilities). |
4.5.2. برگشت
/privet/capabilities API returns device capabilities in the Cloud Device Description (CDD) JSON format (see the CDD document for details). Printers at minimum MUST return a list of supported types here. For example, a Cloud Ready printer that is currently online may return something like this (at minimum):{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" }, { "content_type": "*/*" } ] } }and when it's disconnected from the server, it may return:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }
Note : Printers express supported content type priority using order. For example, in the samples above, the printer specifies that it prefers "application/pdf" data over "image/pwg-raster" and "image/jpeg". Clients should respect printer prioritization if possible (see the CDD document for details).
4.5.3. Errors
/privet/capabilities API may return following errors (see Errors section for details):Error | شرح |
---|---|
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If the device is not exposing the /privet/capabilities API, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
4.6. Errors
Errors are returned from the above APIs in the following format:Value name | Value type | شرح |
---|---|---|
error | string | Error type (defined per API) |
description | string (optional) | Human readable description of the error. |
server_api | string (optional) | In case of server error, this field contains the server API that failed. |
server_code | int (optional) | In case of server error, this field contains that error code that the server returned. |
server_http_code | int (optional) | In case of server HTTP error, this field contains HTTP error code server returned. |
timeout | int (optional) | Number of seconds for client to wait before retrying (for recoverable errors only). Client MUST randomize actual timeout from this value to a value that is + 20%. |
All APIs MUST return HTTP 400 error if X-Privet-Token header is missing.
HTTP/1.1 400 Missing X-Privet-Token header.
Example 1:
{ "error": "server_error", "description": "Service unavailable", "server_api": "/submit", "server_http_code": 503 }
Example 2:
{ "error": "printer_busy", "description": "Printer is currently printing other job", "timeout": 15 }
5. Printer API
One of the device types this protocol supports is type printer. Devices supporting this type MAY implement some functionality specific to printers. Ideally, printing to cloud-ready printers will go through a Cloud Print server:
In some cases a client may need to send a document locally. It may be needed when client does not have a Google ID or is unable to talk to the Cloud Print server. In such case, the print job will be submitted locally to the printer. The printer, in turn, will use the Cloud Print service for job queueing and conversion. The printer will re-post the job submitted locally to the Cloud Print service and then request it, since it was submitted through the cloud. This process will provide a flexible user experience in terms of service (conversion) and print job management/tracking.
Since the Cloud Print service implements conversion, the printer SHOULD advertise supporting all input formats ("*/*") among the list of the supported content types:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "*/*" } ] } }
In some cases a completely offline solution is desired. Since printers support a limited number of input formats, a client will need to convert documents to a few natively supported printer formats.
This spec REQUIRES all printers to support at least the PWG Raster ("image/pwg-raster") format for the offline printing case. A printer may support other formats (for example JPEG) and if a client supports it, it may send documents in that format. The printer MUST expose supported types through the /capabilities API, for example:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }There are two ways a client may initiate printing over the local network.
Simple printing - client sends the document over the local network to /submitdoc API (without specifying the job_id parameter). The submitted document will be printed using default print ticket settings and no print job statuses are needed. If the printer ONLY supports this type of printing, it MUST advertise ONLY /submitdoc API in the /privet/info API response.
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
Advanced printing - client should first create a print job on the printer by calling the /privet/printer/createjob API with a valid CJT job ticket in the request. The printer MUST store the print ticket in memory and return a job_id back to the client. Then the client will call the /printer/submitdoc API and specify the previously received job_id . At that time the printer will start printing. The client will poll the printer for print job status by calling the /privet/printer/jobstate API.
In a multi-client environment, there is no guarantee how this API is called. It is possible for one client to call /createjob between another client's /createjob->/submitdoc calls. To eliminate possible deadlocks and improve usability, we recommended having a small queue of pending print jobs on the printer (at least 3-5):
- /createjob takes the first available spot in the queue.
- Job lifetime (in the queue) is at least 5 minutes.
- If all spots in the queue are taken, then the oldest, non-printing job shall be removed and a new one will be placed there.
- If there is a print job currently printing on the device (simple or advanced printing), /submitdoc should return status busy and propose a timeout to retry this print job.
- If /submitdoc refers to a job that has been removed from the queue (due to replacement or timeout), the printer should return an error invalid_print_job and the client will retry the process from the /createjob step. The client MUST wait for a random timeout period of up to 5 seconds before retrying.
If memory constraints prevent storing multiple pending jobs on the device, it is possible to have a queue of 1 print job long. It should still follow the same protocol as above. After a job has completed or failed with an error, the printer should store information about the job's status for at least 5 minutes. The queue size for storing completed job statuses should be at least 10. If there are more job statuses that need to be stored, the oldest one may be removed from the queue before the 5 minute timeout.
Note: For now clients will poll for job status. In the future, we may require the printer to send TXT DNS notification when ANY print job status has changed.
5.1. /privet/printer/createjob API
/privet/printer/createjob API is OPTIONAL (see Simple Printing above). It is an HTTP POST request. /privet/printer/createjob API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/createjob" url:
POST /privet/printer/createjob HTTP/1.1When receiving /privet/printer/createjob API call, the printer MUST create a new print job ID, store the received print ticket in the CJT format, and return print job id back to the client.
5.1.1. Input
/privet/printer/createjob API has no input parameters in URL. The request body should contain the print job ticket data in CJT format.5.1.2. برگشت
/privet/printer/createjob API returns the following data:Value name | Value type | شرح |
---|---|---|
job_id | string | ID of the newly created print job. |
expires_in | int | Number of seconds this print job is valid. |
Example:
{ "job_id": "123", "expires_in": 600 }
5.1.3. Errors
/privet/printer/createjob API may return the following errors (see Errors section for details):Error | شرح |
---|---|
invalid_ticket | Submitted print ticket is invalid. |
printer_busy | Printer is busy and can't currently process /createjob. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/createjob it MUST return HTTP 404 error. If X-Privet-Token header is missing, the device MUST return HTTP 400 error.
5.2. /privet/printer/submitdoc API
/privet/printer/submitdoc API is REQUIRED to implement printing over a local network (offline or repost to Cloud Print). It is an HTTP POST request. /privet/printer/submitdoc API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/submitdoc" url:POST /privet/printer/submitdoc HTTP/1.1When receiving the /privet/printer/submitdoc API call, the printer should start printing. If it is unable to begin printing, it MUST return the error printer_busy and a recommended timeout period for the client to wait before trying again.
If the printer is not able to hold all of the data in its internal buffer, it SHOULD use TCP mechanisms to slow down data transfer until it prints a portion of the document, making part of the buffer available again. (For example, the printer may set windowsize=0 on TCP layers, which will make the client wait.)
Submitting a document to the printer may take a significant amount of time. The client should be able to check the state of the printer and job (advanced printing) while printing is in progress. In order to do that, the printer MUST allow the client to call the /privet/info and /privet/printer/jobstate APIs while processing /privet/printer/submitdoc API calls. It is recommended for all clients to start a new thread to execute the /privet/printer/submitdoc API call, so that the main thread can use the /privet/info and /privet/printer/jobstate APIs to check printer and job states.
Note : Upon completion or abortion of the local print job, it is strongly recommended (and will be required in a future version of this spec) to report the final state of the job to the /cloudprint/submit interface for accounting and user experience purposes. The parameters "printerid", "title", "contentType" and "final_semantic_state" (in PrintJobState format) are required, and the parameters "tag" (repeated parameter) and "ticket" (the ticket of the job in CloudJobTicket format). Note that the provided PrintJobState must actually be final, ie its type must be DONE or ABORTED, and a cause must be provided in the case that it is ABORTED (see JobState for details). Also note that this use of the /cloudprint/submit interface to report local print jobs is not mentioned in its specification because that section is intended to describe the interface's primary use: submitting a print job with the document to print provided in the "content" parameter.
5.2.1. Input
/privet/printer/submitdoc API has the following input parameters:نام | Value |
---|---|
job_id | (optional) Print job id. May be omitted for simple printing case (see above). Must match the one returned by the printer. |
user_name | (optional) Human readable user name. This is not definitive, and should only be used for print job annotations. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
client_name | (optional) Name of the client application making this request. For display purposes only. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
job_name | (optional) Name of the print job to be recorded. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
offline | (optional) Could only be "offline=1". In this case printer should only try printing offline (no re-post to Cloud Print server). |
Request body should contain a valid document for printing. "Content-Length" should include the correct length of the request. "Content-Type" header should be set to document MIME type and match one of the types in the CDD (unless CDD specifies "*/*").
Clients are HIGHLY recommended to provide a valid user name (or email), a client name and a job name with this request. Those fields are only used in UIs to improve user experience.
5.2.2. Return
/privet/printer/submitdoc API returns following data:Value name | Value type | شرح |
---|---|---|
job_id | string | ID of the newly created print job (simple printing) or job_id specified in the request (advanced printing). |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | Content-type of the submitted document. |
job_size | int 64 bit | Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
Example:
{ "job_id": "123", "expires_in": 500, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
5.2.3. Errors
/privet/printer/submitdoc API may return the following errors (see Errors section for details):Error | شرح |
---|---|
invalid_print_job | Invalid/expired job id is specified in the request. Retry after timeout. |
invalid_document_type | Document MIME-type is not supported by the printer. |
invalid_document | Submitted document is invalid. |
document_too_large | Document exceeds maximum size allowed. |
printer_busy | Printer is busy and can't currently process document. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility) |
user_cancel | User explicitly cancelled printing process from the device. |
server_error | Posting document to Cloud Print has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If the device is not exposing /privet/printer/submitdoc, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
Note : /privet/printer/submitdoc API may require special handling on printer side (because of the large payload attached). In some cases (depends on the printer HTTP server implementation and platform), printer may close socket BEFORE returning HTTP error. In other, printer may return 503 error (instead of Privet error). Printers SHOULD try as much as possible to return Privet. However, every client implementing Privet specification SHOULD be able to handle socket close (no HTTP error) and 503 HTTP error cases for /privet/printer/submitdoc API. In this case, client SHOULD handle it as a Privet "printer_busy" error with "timeout" set to 15 seconds. To avoid infinite retries, client may stop retrying after a reasonable number of attempts (for example, 3).
5.3. /privet/printer/jobstate API
/privet/printer/jobstate API is OPTIONAL (see Simple Printing above). It is an HTTP GET request. /privet/printer/jobstate API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/jobstate" url:GET /privet/printer/jobstate HTTP/1.1When receiving a /privet/printer/jobstate API call, a printer should return the status of the requested print job or invalid_print_job error.
5.3.1. Input
/privet/printer/jobstate API has following input parameters:نام | Value |
---|---|
job_id | Print job ID to return status for. |
5.3.2. برگشت
/privet/printer/jobstate API returns the following data:Value name | Value type | شرح |
---|---|---|
job_id | string | Print job id there status information is for. |
state | string | draft - print job has been created on the device (no /privet/printer/submitdoc calls have been received yet). queued - print job has been received and queued, but printing has not started yet. in_progress - print job is in the progress of printing. stopped - print job has been paused, but can be restarted manually or automatically. done - print job is done. aborted - print job failed. |
description | string | (optional) Human readable description of the print job status. Should include additional information if state < is stopped or aborted . The semantic_state field usually provides better and more meaningful description to the client. |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | (optional) Content-type of the submitted document. |
job_size | int 64 bit | (optional) Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
server_job_id | string | (optional) ID of the job returned from the server (if job has been posted to Cloud Print service). Omitted for offline printing. |
semantic_state | JSON | (optional) Semantic state of the job in PrintJobState format. |
Example (printing by reporting through Cloud Print):
{ "job_id": "123", "state": "in_progress", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "server_job_id": "1111-2222-3333-4444" }
Example (offline printing error):
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
Example (print job aborted by the user):
{ "job_id": "123", "state": "aborted", "description": "User action", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "ABORTED", "user_action_cause": {"action_code": "CANCELLED"} }, "pages_printed": 7 } }
Example (print job stopped due to out of paper). Notice the reference to the device state. The client will need to call the /privet/info API to get more details about the device state:
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": "123456", "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "STOPPED", "device_state_cause": {"error_code": "INPUT_TRAY"} }, "pages_printed": 7 } }
5.3.3. Errors
/privet/printer/jobstate API may return the following errors (see Errors section for details):Error | شرح |
---|---|
invalid_print_job | Invalid/expired job ID is specified in the request. |
server_error | Getting print job status (for print jobs posted to Cloud Print) has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/jobstate, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
6. Appendix
6.1. Default behavior and settings
This section will explain the default behavior we expect from ALL Privet-compatible devices.- Out-of-the-box devices should support only /privet/info and /privet/register APIs. All other APIs (eg /privet/accesstoken, local printing) should be disabled.
- Registration requires physical interaction with a device.
- User MUST take a physical action on the device (eg, pressing a button) to confirm their access to the device.
- After the user takes the action noted above, the printer should send the /cloudprint/register request. It should not send this request until after the action is taken (see Sequence Diagram 1).
- If the device is processing a /privet/register request (for instance, waiting on the action above), it must reject all other /privet/register requests. The device MUST return the device_busy error in this case.
- The device should timeout any /register request that does not receive the physical action mentioned above within 60 seconds. The device MUST return the confirmation_timeout error in this case.
- Optional: Recommended but not required, the following may improve user experience:
- The printer might flash a light or its screen to indicate that the user needs to take an action to confirm registration.
- The printer might state on its screen that 'it is being registered to Google Cloud Print for user ' abc@def.com ' - press OK to continue', where abc@def.com is the user parameter from the /register API call. This would make it clearer to a user that:
- it is their registration request that they are confirming
- what is happening if s/he didn't trigger the request.
- In addition to a physical action to confirm from the printer (eg, 'Press the OK button'), a printer may also offer the user a button to cancel the request (eg, 'Press Cancel to reject'). This would allow users who did not trigger the registration request to cancel it before the 60 second timeout. The device MUST return the user_cancel error in this case.
- Ownership transfers:
- The device may be deleted explicitly from the Cloud service.
- If the device receives success, but no device description as a result of /cloudprint/printer (for GCP) call, it MUST revert to default (out-of-the-box) mode.
- If the device's credentials no longer work (explicitly because of "invalid credentials" response from the server), it MUST revert to default (out-of-the-box) mode.
- Local factory reset MUST clear device's credentials and set it to default state.
- Optional: The device may provide a menu item to clear credentials and put it into default mode.
- Devices supporting XMPP notifications MUST include the ability to ping the server. The ping timeout MUST be controllable from the server through "local_settings".
- The device may explicitly ping the server (/cloudprint/printer API for GCP, in addition to XMPP pings) no more often than once a day (24 hours) to make sure they are in sync. It is recommended to randomize the check window within 24-32 hour window.
- Optional: For Cloud Print devices, it is recommended but not required to have a manual way (button) to allow the user to initiate a check for new print jobs from the device. Some printers already have this.
- Optional. Enterprise printers may have an option to disable local discovery completely. In such case, the device MUST update these local settings on the server. New local settings MUST be empty (setting "local_discovery" to "false", means that it can be re-enabled from the GCP Service).
6.1.2 Default Registration Diagram
6.2. XSSI and XSRF attacks and prevention
This section will explain the possibility of XSSI and XSRF attacks on the device and how to protect from them (including token generation techniques).More details are here: http://googleonlinesecurity.blogspot.com/2011/05/website-security-for-webmasters.html
Normally, XSSI and XSRF attacks are possible when a site is using cookie authentication mechanisms. While Google doesn't use cookies with their Cloud Print Service, such attacks are still possible. Local network access, by design, implicitly trusts requests.
6.2.1. XSSI
It is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and to try to call the Privet API using "src=<api name>" inside of a <script> tag:<script type="text/javascript" src="http://192.168.1.42:8080/privet/info"></script>Without protection, malicious websites would be able to execute API calls and access results.
To prevent this type of attack, ALL Privet API calls MUST require the "X-Privet-Token" header in the request. "src=<api>" script tags are not able to add headers, effectively guarding against this type of attack.
6.2.2. XSRF
http://en.wikipedia.org/wiki/Cross-site_request_forgeryIt is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and try to call Privet API using an <iframe>, forms, or some other cross-website loading mechanism. Attackers would not be able to access the results of the request, but if the request would perform an action (eg printing), they could trigger it.
To prevent this attack, we require the following protection:
- Leave /privet/info API open to XSRF
- /privet/info API MUST NOT perform any actions on the device
- Use /privet/info API to receive x-privet-token
- All other APIs MUST check for a valid x-privet-token in "X-Privet-Token" header.
- x-privet-token SHOULD be valid for only 24 hours.
Even if an attacker is able to execute the /privet/info API, they would not be able to read x-privet-token from the response and therefore would not be able to call any other API.
It is strongly recommended to generate the XSRF token using the following algorithm:
XSRF_token = base64( SHA1(device_secret + DELIMITER + issue_timecounter) + DELIMITER + issue_timecounter )
XSRF Token Generation Elements:
- DELIMITER is a special character, usually ':'
- issue_timecounter is a number of seconds since some event (epoch for timestamp) or device boot time (for CPU counters). issue_timecounter is constantly increasing when the device is up and running (see token verification below).
- SHA1 - hash function using SHA1 algorithm
- base64 - base64 encoding
- device_secret - secret specific to the device. Device secret MUST be updated on every restart.
Recommended ways to generate device secret:
- Generate a new UUID on every restart
- Generate a 64 bit random number on every restart
The device is not required to store all of the XSRF tokens it has issued. When the device needs to verify a XSRF token for validity, it should base64-decode the token. Get the issue_timecounter from the second half (cleartext), and try to produce SHA1 hash of device_secret + DELIMITER + issue_timecounter where issue_timecounter is from the token. If the newly generated SHA1 matches the one in the token, device must now check if the issue_timecounter is within the validity period from (24 hours) of the current time counter. To do so, device takes the current time counter (CPU counter for example) and subtracts issue_timecounter from it. The result MUST be the number of seconds since token issue.
Important: This is the recommended way to implement XSRF protection. Clients of the Privet specification shall not try to understand XSRF token, instead they shall treat is as a blackbox. Figure 6.2.3 illustrates a recommended way to implement the X-Privet-Token and verification of a typical request.