Статьи

вивчаємо WebDav

  1. Зміст статті Якби в якості введення я почав розписувати гідності хмарних сховищ даних, ти б подумав,...
  2. можливі рішення
  3. Підключаємося до Yandex.disk + створюємо колекцію
  4. видалення об'єкта
  5. Завантаження файлу
  6. Завантаження файлу на сервер
  7. Підсумки

Зміст статті

Якби в якості введення я почав розписувати гідності хмарних сховищ даних, ти б подумав, що мене тільки що розморозили після двадцятирічного анабіозу або що я серйозно зловживаю снодійними :). Тому скажу коротко, по-програмістські: коли переді мною постало завдання зробити програму, яка могла б без прив'язки до API конкретного сервісу працювати з файлами на безлічі сховищ (йшлося про бекапе), виявилося, що це не так просто. Про всі тонкощі і підводні камені виконаної роботи я вирішив тобі розповісти в цій статті.

WebDAV

WebDAV (Web Distributed Authoring and Versioning) - це протокол для передачі даних і роботи з ними, побудований поверх HTTP 1.1. Тут слід зауважити, що передача може бути як захищеної, так і незахищеною. У самому протоколі захищеність відсутня, але вона може бути додана через реалізацію аутентифікації на веб-сервері і шифрування за допомогою SSL, отже, в такому випадку буде використовуватися не HTTP, а HTTPS.

Спочатку DAV розроблявся для спільного створення і редагування веб-сторінок, але в процесі використання він знайшов застосування в якості мережевої розподіленої файлової системи, ефективної для роботи в високонавантаженої середовищі і підтримує нестійке з'єднання. Таким чином, DAV підходить для управління файлами на веб-серверах, іншими словами, реалізації хмарних сховищ інформації, де і був застосований. З його допомогою можна виконувати основні операції над файлами, що містяться на сервері, проводити розширені операції, як то: блокування, отримання метаданих, контроль версій і інші. Цей протокол став заміною для старого доброго FTP, чий час підійшло до кінця.

WebDAV надає сім команд:

  • PROPFIND - отримання властивостей об'єкта на сервері в форматі XML;
  • PROPPATCH - зміна властивостей об'єкта;
  • MKCOL - створити папку на сервері;
  • COPY - копіювання на стороні сервера;
  • MOVE - переміщення на стороні сервера;
  • LOCK - заблокувати об'єкт;
  • UNLOCK - зняти блокування з об'єкта.

Таким чином, WebDAV дозволяє змінювати властивості зберігаються на сервері об'єктів, виконувати пошук з урахуванням властивостей, блокувати об'єкт (в нашому випадку - файл) для організації можливості його редагування тільки одним користувачем в розподіленої середовищі, в якій доступ можуть мати багато користувачів, керувати версіями файлів (за допомогою успадкованих команд check -in, -out), а також виробляти розширений контроль доступу до файлів на основі списків.

Крім того, WebDAV підтримує успадковані команди: GET - для скачування файлу, PUT - для заливки на сервер і DELETE - для видалення об'єкта. Ми не будемо розглядати всі команди; в моєму випадку для реалізації функціоналу утиліти мені знадобилося лише чотири.

Нині в розробці протоколу беруть участь Microsoft, Mozilla, Novell, IBM та інші. Тому не варто дивуватися тому, що підтримка WebDAV присутня в багатьох продуктах Microsoft (в тому числі Internet Explorer, провіднику, веб-сервері IIS і інших), браузері Mozilla Firefox, продуктах фірми Novell, IBM. Додатково, за допомогою установки плагінів «подружити» з протоколом можна Total Commander і FAR.

Як уже було згадано, в Windows віддалене сховище WebDAV можна підключити в провідник як додатковий диск. Подібним чином можна вчинити в OS X, організувавши підключення до WebDAV-сервера як додаткову директорію в браузері Finder.

можливі рішення

Переді мною стояло завдання підключитися і організувати роботу з даними на двох файлових сховищах: Яндекс.Діск і Dropbox. Обидва ці сервісу підтримують роботу по протоколу WebDAV. Реєструючи пошту на Яндексі, ти автоматом отримуєш доступ до 10 Гб хмарного сховища, до якого можна підключитися не тільки через стандартний клієнт, але і за допомогою сторонньої тулзи (наприклад, своєї програми) за допомогою протоколу WebDAV. При реєстрації на Dropbox ти отримуєш 5 Гб дискового простору, яке можна використовувати через стандартний клієнт. Однак, щоб отримати доступ до сховища по WebDAV, треба пройти додаткову реєстрацію. У підсумку, як з'ясувалося, цей доступ не безкоштовний, проте після реєстрації дається вільний доступ на два тижні. Розміри сховищ можна збільшувати: або через доплату, або за допомогою участі в різних акціях, що проводяться сервісами, наприклад знаходити баги і повідомляти про них розробникам.

Коли мені знадобилося написати програму для роботи з WebDAV-протоколу, я першим ділом заглянув в Win32 API, щоб подивитися, чи є там функції для цього, подібно до наявним для роботи з FTP. Забігаючи вперед, відзначу, що терміни у мене стояли стислі, тому використовувати функції рівня API я не збирався. Як і слід було очікувати, в Win32 API, починаючи з версії для Windows Vista, входить WebDAV API . У нього входить одне перерахування, три структури і набір функцій. Я подумав, що це хороший знак, оскільки на основі стандартного API неодмінно є більш високорівневі рішення і мені не доведеться засиджуватися з функціями API-інтерфейсу.

Тут під руку попалася Delphi XE3, і я вирішив перевірити, які інструменти для роботи з протоколом WebDAV є у неї. Виявилося, що в ній (на вкладці Indy Clients палітри компонентів) є компонент IdWebDav. Я вже подумав, що на цьому дослідження закінчилися ... Але виявилося, що цей компонент ні в яку не коннектітся до Яндексу (Яндекс.Діск був для мене більш пріоритетним сервісом, тому всі тести я в першу чергу проводив на ньому).

Потім я вирішив скористатися старою, але перевіреної часом мережевий бібліотекою Synapse для Delphi. До того ж в Рунеті є прекрасний сайт, що містить кілька статей, присвячених цій Лібе, www.webdelphi.ru . На перших порах робота рухалася добре, і мені вдалося реалізувати кілька функцій протоколу: створення папки, скачування файлів, отримання властивостей об'єктів. Але найголовнішу функцію - завантаження файлів на сервер з локального компа - реалізувати так і не вдалося. Стало сумно: в інтернеті про це протоколі тямущою інформації немає. Bing знайшов кілька платних наборів компонентів для роботи з мережею, однією з яких я заради інтересу вирішив скористатися, щоб з'ясувати, чи реально завантажити файл на Яндекс.Діск. Цією либой виявилася Clever Internet Suite. Створивши компонент класу clWebDav, одним рядком коду вдалося закинути файл на сервер:

clWebDav.Put ( ' https://webdav.yandex.ru/1.jpg ', Stream);

де stream - файловий потік, попередньо створений для читання.

Прекрасно, але відштовхує вартість цієї ліби: більше 500 у. е., що не їсти гуд. Якщо ти захочеш скористатися цим способом, то зверни увагу на версію бібліотеки: до Яндексу можна підключитися тільки за допомогою версії 7.0 і вище, якщо скористатися поширеною на просторах Мережі версією 6.0, то завантаження даних на сервер не вдасться. На цьому «гратися» з Delphi мені набридло, і я вирішив звернутися до dotNET і C #.

Підключаємося до Yandex.disk + створюємо колекцію

Оскільки WebDAV працює поверх HTTP / S, я вирішив скористатися класами HttpWebRequest і HttpWebResponse, які входять в .NET Framework починаючи з версії 2.0. При цьому ми будемо використовувати .NET Framework 4.0 - чому, скажу нижче. Коротко кажучи, перший з перерахованих класів становить HTTP-запит, другий - HTTP-відповідь. Наше завдання - правильно сформувати запит таким чином, щоб його міг зрозуміти WebDAV-сервер. Щоб дізнатися, як правильно оформляти запити WebDAV-сервера, звернемося до документації Яндекса по використанню протоколу WebDAV .

Наступним дією напишемо невелику програму, здатну виконати чотири операції: створити папку на віддалений хост, завантажити об'єкт, скачати об'єкт і видалити об'єкт. Цих операцій досить для більшості додатків, які вирішують виробничі завдання. Для простоти створимо WinForms-додаток. У парі слів розповім про свою проге. Вона являє собою консольний додаток, що запускається батник за розкладом. Її основна дія - це заливка файлів на віддалений хост, при цьому в її завдання входить коректна обробка маски для вибору файлів, а також обробка шляхів, за якими вони розміщені, плюс правильне створення в хмарі ієрархії папок, подібної розміщеної на локальному диску. Крім того, оскільки програма працює в автоматичному режимі, вона створює файл з балками. У нашій сьогоднішній програмі ми опустимо ці дії (очевидно, що вони не належать до теми) і сконцентруємося на протоколі WebDAV.

Зверни увагу: при створенні заготовки проекту за основу краще взяти .NET Framework 4.0. І хоча підтримка WebDAV з'явилася ще в другій версії, по тестах стало видно, що та ж сама програма, перекомпіліровать з використанням .NET 4, працює в два рази швидше, і це стосується швидкості роботи з файлами і їх пересилкою.

Після створення заготовки додатки розмісти на його формі чотири кнопки. Першою операцією, яку ми реалізуємо, буде створення папки (або колекції). Вона найпростіша з усіх. На замітку: хоча Яндекс.Діск працює по захищеному протоколу HTTPS, папку можна створити по HTTP. Також на формі нам знадобляться чотири поля введення: для завдання адреси віддаленого хоста (поки націлюватимемося на Яндекс.Діск: https://webdav.yandex.ru/ ), Для введення імені користувача, пароля (для аутентифікації на Яндексі) і введення імені папки, яку ми хочемо створити в хмарі (рис. 1). Зверни увагу: адреса сервера треба вводити разом із зазначенням протоколу, в даному випадку https: //.

Зверни увагу: адреса сервера треба вводити разом із зазначенням протоколу, в даному випадку https: //

Насамперед в коді підключи простору імен: using System.Net; - для роботи з мережею та using System.IO; - для файлового введення-виведення. Потім створи обробник події натискання на кнопку CreateDir. У нього напиши такий код:

String folder = folderEdit.Text; String url = urlEdit.Text; String userName = nameEdit.Text; String password = passwordEdit.Text; url + = folder; url = url.TrimEnd (); HttpWebRequest request = HttpWebRequest.Create (url) as HttpWebRequest; request.Credentials = new NetworkCredential (userName, password); request.Method = WebRequestMethods.Http.MkCol; HttpWebResponse response = (HttpWebResponse) request.GetResponse (); HttpStatusCode code = response.StatusCode;

Коротенько обговоримо код. На початку для зручності розміщуємо дані з полів введення в змінні: ім'я папки, адреса хоста, ім'я та пароль користувача. Далі формуємо URL-адресу: до адресою хоста додаємо ім'я створюваної папки. Як і у HTTP, у WebDAV є стандартний номер порту - 443, тому його вказувати необов'язково. Тепер на основі URL ми можемо створити об'єкт HTTP-запиту, що робиться в наступному рядку. Після створення треба заповнити деякі його властивості. Тобто необхідно вказати такі дані, які будуть передані сервера в заголовку запиту. Дивимося документацію Яндекса (посилання наведена вище). У число необхідних параметрів входять дані аутентифікації. Яндекс приймає ці дані в двох видах: Basic - логін і пароль, QAuth - токен по протоколу QAuth. Ми виберемо перший шлях. Однак в такому випадку дані повинні бути закодовані. Це здійснює об'єкт класу NetworkCredential, конструктор якого отримує ім'я і пароль у вигляді рядків. Створений об'єкт цього класу привласнюється властивості Credentials об'єкта запиту. Наступним рядком ми повідомляємо, яку команду ми хочемо виконати, - MKCOL. В цьому випадку ніякі дані передавати / отримувати не потрібно, і відразу після цього ми відправляємо запит. Далі ми можемо подивитися, яку відповідь повернув сервер, в разі успіху відповіддю буде рядок Created. У класі HttpWebRequest визначено багато відповідей на всі випадки спільного спілкування клієнта і сервера.

WebDAV-протокол не дозволяє створити кілька вкладених папок за один запит, наприклад / folder1 / folder2 /; можна створити тільки одну папку: / folder1 /. Якщо каталог існує, а відправлений запит намагається створити однойменну директорію, в такому випадку сервер згенерує виняток, яке треба перехопити конструкцією try / catch. У наведеному вище прикладі не відбувається обробка винятків, тому якщо будеш використовувати цей код в своєму додатку, то не забудь її додати. Якщо Вам потрібна, існує каталог чи ні, то для цього можна скористатися запитом PROPFIND, а потім отримати і пропарсіть відповідь сервера, що містить інфу в форматі XML про наявних на сервері об'єктах. Але це вийде довго, і, на мій погляд, краще використовувати запит MKCOL і в разі присутності однойменної папки обробити виняток. Таким чином в своїй консольної утиліти я створюю ієрархію папок. Крім того, якщо однойменний каталог вже існує, відбувається захід у нього.

видалення об'єкта

Видалення файлу і / або директорії по протоколу WebDAV реалізується так само просто, як створення колекції. Для реалізації цього завдання послужить наведений вище код, в якому треба замінити рядок, що задає виконується сервером метод, на наступну:

request.Method = "DELETE";

Як видно, в класі WebRequestMethods.Http відсутня метод Delete, але ми можемо поставити бажаний метод у вигляді рядка. Вона буде відправлена ​​на сервер, головне, щоб він був в змозі обробити і виконати цей метод, а WebDAV-сервер, як ми знаємо, на це здатний.

У цьому випадку також краще використовувати конструкцію try / catch для перехоплення виключення, яке може виникнути через відсутність об'єкту, що видаляється.

Завантаження файлу

Щоб завантажити файл з хмарного сховища по протоколу WebDAV, потрібно виконати не так вже й багато маніпуляцій з наявним кодом. Але для початку закинь який-небудь файл в хмару стандартними засобами (через веб-інтерфейс або десктопний Яндекс-клієнт). За задумом, при скачуванні файлу в четверте (нижня) поле введення ми будемо вводити ім'я файлу, який хочемо закачати. Це ж ім'я дамо файлу-результату на локальному компі. Зауваж, на сервері ми можемо вказати /Software/file.txt і буде отриманий доступ до файлу в папці Software, проте в локальній файловій системі автоматом папка створена не буде, тому її попередньо треба створити. Коротко кажучи, ми будемо качати файл ZuneSetupPkg.exe (незамінна тулза для роботи з Windows Phone, яку частенько доводиться доустанавливать на чужих компах, тому вона завжди у мене під рукою - в хмарі) з кореня Яндекс.Діск в директорію з екзешніком.

У обробнику натиснення на кнопку Download після ініціалізації змінних, створення об'єкта-запиту і завдання повноважень (Credentials) постав тип методу: GET (див. Исходник в матеріалах до номера). Потім, отримавши відповідь сервера (об'єкт класу HttpWebResponse), оголосимо змінні для читання даних:

int byteTransferRate = 8192; // Розмір буфера byte [] bytes = new byte [byteTransferRate]; // Буфер int bytesRead = 0; long totalBytesRead = 0; long contentLength = long.Parse (response.GetResponseHeader ( "Content-Length"));

В останньому рядку коду читаємо з заголовка відповіді від сервера розмір файлу і зберігаємо його в змінну. Далі створюємо файловий потік для запису файлу на диск:

FileStream fs = new FileStream (fileToDownload, FileMode.Create, FileAccess.Write);

Потім отримуємо потік від сервера:

Stream s = response.GetResponseStream ();

Порціями читаємо з нього дані і пишемо їх в файл, поки є що писати:

do {bytesRead = s.Read (bytes, 0, bytes.Length); if (bytesRead> 0) {totalBytesRead + = bytesRead; fs.Write (bytes, 0, bytesRead); }} While (bytesRead> 0);

Після того як всі дані записані в файл, закриваємо обидва потоку і серверний відповідь. Під час зчитування даних ми збільшували змінну totalBytesRead на кількість лічених байт. В цьому випадку при відсутності помилок розмір цієї змінної повинен стати рівним розміру, який ми вважали з заголовка, і якщо це так, то файл викачаний коректно і ми виводимо повідомлення про це (рис. 2), якщо ж розміри не рівні, тоді сталася невдача про це ми теж повідомляємо користувачеві.

Цей код не позбавлений виключень, які треба ловити, серед них: (404) неможливо знайти файл (на сервері), неможливо записати в вказане місце і багато інших.

Завантаження файлу на сервер

Остання операція, без якої наша утиліта буде неповною, - це завантаження файлу на віддалений хост. Це сама «хитра» операція. Обговорені вище операції не спричинили жодного утруднення, але ця виявилася покруче! Я вже розповідав, що з реалізацією завантаження файлу були труднощі при використанні інших засобів розробки. І не все гладко було на C #. Спочатку в документації подивимося, який запит для заливки файлу чекає Яндекс (рис. 3).

В повноцінної програмі треба здійснювати закачування відразу декількох файлів (за бажанням користувача), вибір файлів по масці, створення ієрархії каталогів і, нарешті, обробку помилок. Ми ж, щоб не товкти воду в ступі, все це опустимо і сконцентруємося на завантаженні одного заданого файлу, без створення папок і обробки помилок. Все це залишимо тебе в якості домашнього завдання. Отже, в підготовленій мною проге з обробника натискання на кнопку викликається метод UpdateFile, йому передаються ім'я хоста і ім'я файлу, що, які беруться з відповідних полів введення. Початок самого методу подібно розглянутим вище, однак тепер в заголовку запиту ми передаємо на виконання сервером команду PUT, тобто відкриваємо наше бажання завантажити файл. Якщо при виконанні попередніх запитів ми особливо не спиралися на документацію, то на цей раз вона нам дуже знадобиться: включимо в заголовок запиту всі рекомендовані Яндексом поля, а також деякі додаткові. Отже, розглянемо код заголовка, а потім обговоримо трабли:

request.ContentLength = fileLength; request.KeepAlive = false; request.ReadWriteTimeout = -1; request.Timeout = -1; request.AllowWriteStreamBuffering = false; request.PreAuthenticate = true; request.SendChunked = false; request.ContentType = "application / binary"; request.ProtocolVersion = HttpVersion.Version11; request.ServicePoint.ConnectionLimit = 1; request.AllowAutoRedirect = false; //request.Expect = "100-continue"; request.ServicePoint.Expect100Continue = true; request.Accept = "* / *";

Значення Деяк параметрів віведені методом наукового тику. Деякі Властивості залежався від других. Так, краще відключіті постійне Підключення (другий рядок), бо при цьом генерується віняток про неможлівість одночасної читання и запису в потік. Наступні два Властивості задають тайм-аут для читання и запису в мережевий потік. Значення -1 означає нескінченність. Розмір завантаження може бути невизначено великим, тому ми не можемо загадувати на час, який знадобиться для його завантаження. Наступне властивість: AllowWriteStreamBuffering - дуже цікаве, воно включає або відключає буферизацію даних перед відправленням. При включенні відправляється файл спочатку завантажується в пам'ять, тільки після цього вивантажується на сервер. Дивина цієї властивості полягає в тому, що на деяких хостах можна без проблем, відключивши буферизацию, залити файл, проте на інших буде спливати виняток про необхідність буферизації. Можливо, це пов'язано з якимись настройками реєстру або зв'язку; не виключаю також відмінності між сервісами. У разі якщо буферизація включена і на сервер відправляється великий файл, може не вистачити ресурсів (виняток SystemOutOfMemory). У свою прогу можеш додати прапорець для включення і відключення буферизації. Якщо буферизація відключена, тоді треба включити прапор PreAuthenticate (наступне властивість), за допомогою якого дані аутентифікації відправляються разом з заголовком. Наступний параметр SendChunked (тільки для Яндекс.Діск) дозволяє завантажувати на віддалений хост файли заздалегідь невизначеного розміру, на що Dropbox відповідає винятком. Далі вказуємо тип переданих даних, версію використовуваного протоколу (11 означає 1.1), кількість можливих HTTP-підключень: більше одного ні до чого. Забороняємо автоматичне перенаправлення. Щоб задати наступне рекомендований поле: "Expect: 100-continue", що включає очікування відповіді для запиту завантаження, не можна використовувати закоментувавши властивість, треба використовувати код, який рядком нижче: request.ServicePoint.Expect100Continue = true ;. Останнім властивістю HTTP-заголовка включається маска для прийнятих об'єктів, в нашому випадку приймаються будь-які файли: з довільним ім'ям і розширенням.

Після того як запит сформований, треба отримати мережевий потік, в який ми будемо записувати дані, що відправляються на сервер. Також відкриваємо локальний файл для читання. Виділяємо байтовий буфер для тимчасового зберігання лічених з файлу даних; потім в циклі починаємо читати і відправляти, записуючи дані в потік. Після цього закриваємо мережевий і файловий потоки, в загальному, як зазвичай. Отримавши відповідь від сервера, перевіряємо HTTP-статус на його рівність прапору Created і порівнюємо розмір файлу з кількістю переданих байт; якщо обидві умови виконуються, значить, пересилання успішна, інакше - виникла проблема.

Отримавши відповідь від сервера, перевіряємо HTTP-статус на його рівність прапору Created і порівнюємо розмір файлу з кількістю переданих байт;  якщо обидві умови виконуються, значить, пересилання успішна, інакше - виникла проблема

Підсумки

На цьому розробка нашої утиліти підійшла до кінця. У ній ми реалізували весь планований функціонал - чотири найпотрібніші команди, без яких не може обійтися жоден менеджер управління файлами на віддаленому хості. Ми не стали прив'язуватися до послуг певного хостингу, використовуючи його API, ми розробили універсальний додаток, спілкуватися з сервером по стандартному протоколу WebDAV. Це дозволило нашій програмі, використовуючи один код, підключатися відразу до декількох серверів (я тестував на Yandex.disk і Dropbox). Проте, як ми побачили, різні сервіси дещо по-різному інтерпретують і підтримують протокол.

Подальший розвиток проги надаю тобі, по ходу статті я вказав на можливі покращення: це і завантаження декількох файлів, і створення ієрархії папок, і розпаралелювання завантаження, і багато іншого. Якщо копнути глибше в протокол WebDAV, можна реалізувати інші команди для управління контентом на сервері.

На цій ноті я хочу побажати тобі удачі у всіх справах і бути побільше на свіжому повітрі :). До зустрічі на сторінках] [!

Новости