1/*
2 * Copyright (C) 2012 Intel Corporation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "UnitTestUtils/EWK2UnitTestBase.h"
29#include "UnitTestUtils/EWK2UnitTestServer.h"
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35
36using namespace EWK2UnitTest;
37using namespace WTF;
38
39extern EWK2UnitTestEnvironment* environment;
40
41static const char serverSuggestedFilename[] = "webkit-downloaded-file";
42static const char testFilePath[] = "/test.pdf";
43
44class EWK2DownloadJobTest : public EWK2UnitTestBase {
45public:
46    struct DownloadTestData {
47        const char* fileUrl;
48        const char* destinationPath;
49    };
50
51    static bool fileExists(const char* path)
52    {
53        struct stat buf;
54        return !stat(path, &buf);
55    }
56
57    static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, void*)
58    {
59        if (message->method != SOUP_METHOD_GET) {
60            soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
61            return;
62        }
63
64        Eina_Strbuf* filePath = eina_strbuf_new();
65        eina_strbuf_append(filePath, TEST_RESOURCES_DIR);
66        eina_strbuf_append(filePath, path);
67
68        Eina_File* f = eina_file_open(eina_strbuf_string_get(filePath), false);
69        eina_strbuf_free(filePath);
70        if (!f) {
71            soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
72            soup_message_body_complete(message->response_body);
73            return;
74        }
75
76        size_t fileSize = eina_file_size_get(f);
77
78        void* contents = eina_file_map_all(f, EINA_FILE_POPULATE);
79        if (!contents) {
80            soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
81            soup_message_body_complete(message->response_body);
82            return;
83        }
84
85        soup_message_set_status(message, SOUP_STATUS_OK);
86
87        Eina_Strbuf* contentDisposition = eina_strbuf_new();
88        eina_strbuf_append_printf(contentDisposition, "filename=%s", serverSuggestedFilename);
89        soup_message_headers_append(message->response_headers, "Content-Disposition", eina_strbuf_string_get(contentDisposition));
90        eina_strbuf_free(contentDisposition);
91
92        soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, contents, fileSize);
93        soup_message_body_complete(message->response_body);
94
95        eina_file_map_free(f, contents);
96        eina_file_close(f);
97    }
98
99    static void on_download_requested(void* userData, Evas_Object* webview, void* eventInfo)
100    {
101        DownloadTestData* testData = static_cast<DownloadTestData*>(userData);
102        Ewk_Download_Job* download = static_cast<Ewk_Download_Job*>(eventInfo);
103        ASSERT_EQ(EWK_DOWNLOAD_JOB_STATE_NOT_STARTED, ewk_download_job_state_get(download));
104        ASSERT_EQ(0, ewk_download_job_estimated_progress_get(download));
105        ASSERT_EQ(0, ewk_download_job_elapsed_time_get(download));
106        ASSERT_EQ(0, ewk_download_job_received_data_size_get(download));
107
108        Ewk_Url_Request* request = ewk_download_job_request_get(download);
109        ASSERT_TRUE(request);
110        EXPECT_STREQ(testData->fileUrl, ewk_url_request_url_get(request));
111
112        Ewk_Url_Response* response = ewk_download_job_response_get(download);
113        ASSERT_TRUE(response);
114        EXPECT_STREQ("application/pdf", ewk_url_response_mime_type_get(response));
115
116        EXPECT_STREQ(serverSuggestedFilename, ewk_download_job_suggested_filename_get(download));
117
118        ASSERT_FALSE(fileExists(testData->destinationPath));
119        ewk_download_job_destination_set(download, testData->destinationPath);
120        EXPECT_STREQ(testData->destinationPath, ewk_download_job_destination_get(download));
121    }
122
123    static void on_download_cancelled(void* userData, Evas_Object* webview, void* eventInfo)
124    {
125        fprintf(stderr, "Download was cancelled.\n");
126        ecore_main_loop_quit();
127        FAIL();
128    }
129
130    static void on_download_failed(void* userData, Evas_Object* webview, void* eventInfo)
131    {
132        Ewk_Download_Job_Error* downloadError = static_cast<Ewk_Download_Job_Error*>(eventInfo);
133        fprintf(stderr, "Download error: %s\n", ewk_error_description_get(downloadError->error));
134        ecore_main_loop_quit();
135        FAIL();
136    }
137
138    static void on_download_finished(void* userData, Evas_Object* webview, void* eventInfo)
139    {
140        DownloadTestData* testData = static_cast<DownloadTestData*>(userData);
141        Ewk_Download_Job* download = static_cast<Ewk_Download_Job*>(eventInfo);
142
143        ASSERT_EQ(1, ewk_download_job_estimated_progress_get(download));
144        ASSERT_EQ(EWK_DOWNLOAD_JOB_STATE_FINISHED, ewk_download_job_state_get(download));
145        ASSERT_GT(ewk_download_job_elapsed_time_get(download), 0);
146        ASSERT_GT(ewk_download_job_received_data_size_get(download), 0);
147
148        ASSERT_TRUE(fileExists(testData->destinationPath));
149
150        ecore_main_loop_quit();
151    }
152};
153
154TEST_F(EWK2DownloadJobTest, ewk_download)
155{
156    std::unique_ptr<EWK2UnitTestServer> httpServer = std::make_unique<EWK2UnitTestServer>();
157    httpServer->run(serverCallback);
158
159    CString fileUrl = httpServer->getURLForPath(testFilePath);
160
161    char destinationDirectory[] = "/tmp/ewk2_download_job-XXXXXX";
162    ASSERT_TRUE(mkdtemp(destinationDirectory));
163    char destinationPath[64];
164    snprintf(destinationPath, sizeof(destinationPath), "%s/pdf-file", destinationDirectory);
165
166    DownloadTestData userData = { fileUrl.data(), destinationPath };
167    ASSERT_FALSE(fileExists(destinationPath));
168
169    evas_object_smart_callback_add(webView(), "download,request", on_download_requested, &userData);
170    evas_object_smart_callback_add(webView(), "download,cancel", on_download_cancelled, &userData);
171    evas_object_smart_callback_add(webView(), "download,failed", on_download_failed, &userData);
172    evas_object_smart_callback_add(webView(), "download,finished", on_download_finished, &userData);
173
174    // Download test pdf
175    ewk_view_url_set(webView(), fileUrl.data());
176    ecore_main_loop_begin();
177
178    // Clean up
179    unlink(destinationPath);
180    rmdir(destinationDirectory);
181}
182