diff options
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/child/ftp_directory_listing_response_delegate.h | 3 | ||||
-rw-r--r-- | webkit/child/webkit_child.gyp | 8 | ||||
-rw-r--r-- | webkit/child/webkitplatformsupport_impl.cc | 918 | ||||
-rw-r--r-- | webkit/child/webkitplatformsupport_impl.h | 156 | ||||
-rw-r--r-- | webkit/child/websocketstreamhandle_bridge.h | 37 | ||||
-rw-r--r-- | webkit/child/websocketstreamhandle_delegate.h | 44 | ||||
-rw-r--r-- | webkit/child/websocketstreamhandle_impl.cc | 197 | ||||
-rw-r--r-- | webkit/child/websocketstreamhandle_impl.h | 40 | ||||
-rw-r--r-- | webkit/child/weburlloader_impl.cc | 871 | ||||
-rw-r--r-- | webkit/child/weburlloader_impl.h | 51 |
10 files changed, 2323 insertions, 2 deletions
diff --git a/webkit/child/ftp_directory_listing_response_delegate.h b/webkit/child/ftp_directory_listing_response_delegate.h index af18f38..254ca80 100644 --- a/webkit/child/ftp_directory_listing_response_delegate.h +++ b/webkit/child/ftp_directory_listing_response_delegate.h @@ -12,7 +12,6 @@ #include "base/basictypes.h" #include "third_party/WebKit/public/platform/WebURLResponse.h" -#include "webkit/child/webkit_child_export.h" namespace blink { class WebURLLoader; @@ -23,7 +22,7 @@ class GURL; namespace webkit_glue { -class WEBKIT_CHILD_EXPORT FtpDirectoryListingResponseDelegate { +class FtpDirectoryListingResponseDelegate { public: FtpDirectoryListingResponseDelegate(blink::WebURLLoaderClient* client, blink::WebURLLoader* loader, diff --git a/webkit/child/webkit_child.gyp b/webkit/child/webkit_child.gyp index cf341e52..6183b7b 100644 --- a/webkit/child/webkit_child.gyp +++ b/webkit/child/webkit_child.gyp @@ -67,6 +67,14 @@ 'webkit_child_export.h', 'webkit_child_helpers.cc', 'webkit_child_helpers.h', + 'webkitplatformsupport_impl.cc', + 'webkitplatformsupport_impl.h', + 'websocketstreamhandle_bridge.h', + 'websocketstreamhandle_delegate.h', + 'websocketstreamhandle_impl.cc', + 'websocketstreamhandle_impl.h', + 'weburlloader_impl.cc', + 'weburlloader_impl.h', 'weburlrequest_extradata_impl.cc', 'weburlrequest_extradata_impl.h', 'weburlresponse_extradata_impl.cc', diff --git a/webkit/child/webkitplatformsupport_impl.cc b/webkit/child/webkitplatformsupport_impl.cc new file mode 100644 index 0000000..1c55e13 --- /dev/null +++ b/webkit/child/webkitplatformsupport_impl.cc @@ -0,0 +1,918 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/child/webkitplatformsupport_impl.h" + +#include <math.h> + +#include <vector> + +#include "base/allocator/allocator_extension.h" +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/message_loop/message_loop.h" +#include "base/metrics/histogram.h" +#include "base/metrics/sparse_histogram.h" +#include "base/metrics/stats_counters.h" +#include "base/platform_file.h" +#include "base/process/process_metrics.h" +#include "base/rand_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/synchronization/lock.h" +#include "base/sys_info.h" +#include "base/time/time.h" +#include "grit/blink_resources.h" +#include "grit/webkit_resources.h" +#include "grit/webkit_strings.h" +#include "net/base/data_url.h" +#include "net/base/mime_util.h" +#include "net/base/net_errors.h" +#include "third_party/WebKit/public/platform/WebData.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "ui/base/layout.h" +#include "webkit/child/webkit_child_helpers.h" +#include "webkit/child/websocketstreamhandle_impl.h" +#include "webkit/child/weburlloader_impl.h" +#include "webkit/common/user_agent/user_agent.h" + +#if defined(OS_ANDROID) +#include "base/android/sys_utils.h" +#endif + +#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN) +#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" +#endif + +using blink::WebData; +using blink::WebLocalizedString; +using blink::WebString; +using blink::WebSocketStreamHandle; +using blink::WebURL; +using blink::WebURLError; +using blink::WebURLLoader; + +namespace { + +// A simple class to cache the memory usage for a given amount of time. +class MemoryUsageCache { + public: + // Retrieves the Singleton. + static MemoryUsageCache* GetInstance() { + return Singleton<MemoryUsageCache>::get(); + } + + MemoryUsageCache() : memory_value_(0) { Init(); } + ~MemoryUsageCache() {} + + void Init() { + const unsigned int kCacheSeconds = 1; + cache_valid_time_ = base::TimeDelta::FromSeconds(kCacheSeconds); + } + + // Returns true if the cached value is fresh. + // Returns false if the cached value is stale, or if |cached_value| is NULL. + bool IsCachedValueValid(size_t* cached_value) { + base::AutoLock scoped_lock(lock_); + if (!cached_value) + return false; + if (base::Time::Now() - last_updated_time_ > cache_valid_time_) + return false; + *cached_value = memory_value_; + return true; + }; + + // Setter for |memory_value_|, refreshes |last_updated_time_|. + void SetMemoryValue(const size_t value) { + base::AutoLock scoped_lock(lock_); + memory_value_ = value; + last_updated_time_ = base::Time::Now(); + } + + private: + // The cached memory value. + size_t memory_value_; + + // How long the cached value should remain valid. + base::TimeDelta cache_valid_time_; + + // The last time the cached value was updated. + base::Time last_updated_time_; + + base::Lock lock_; +}; + +} // anonymous namespace + +namespace webkit_glue { + +static int ToMessageID(WebLocalizedString::Name name) { + switch (name) { + case WebLocalizedString::AXAMPMFieldText: + return IDS_AX_AM_PM_FIELD_TEXT; + case WebLocalizedString::AXButtonActionVerb: + return IDS_AX_BUTTON_ACTION_VERB; + case WebLocalizedString::AXCheckedCheckBoxActionVerb: + return IDS_AX_CHECKED_CHECK_BOX_ACTION_VERB; + case WebLocalizedString::AXDateTimeFieldEmptyValueText: + return IDS_AX_DATE_TIME_FIELD_EMPTY_VALUE_TEXT; + case WebLocalizedString::AXDayOfMonthFieldText: + return IDS_AX_DAY_OF_MONTH_FIELD_TEXT; + case WebLocalizedString::AXHeadingText: + return IDS_AX_ROLE_HEADING; + case WebLocalizedString::AXHourFieldText: + return IDS_AX_HOUR_FIELD_TEXT; + case WebLocalizedString::AXImageMapText: + return IDS_AX_ROLE_IMAGE_MAP; + case WebLocalizedString::AXLinkActionVerb: + return IDS_AX_LINK_ACTION_VERB; + case WebLocalizedString::AXLinkText: + return IDS_AX_ROLE_LINK; + case WebLocalizedString::AXListMarkerText: + return IDS_AX_ROLE_LIST_MARKER; + case WebLocalizedString::AXMediaDefault: + return IDS_AX_MEDIA_DEFAULT; + case WebLocalizedString::AXMediaAudioElement: + return IDS_AX_MEDIA_AUDIO_ELEMENT; + case WebLocalizedString::AXMediaVideoElement: + return IDS_AX_MEDIA_VIDEO_ELEMENT; + case WebLocalizedString::AXMediaMuteButton: + return IDS_AX_MEDIA_MUTE_BUTTON; + case WebLocalizedString::AXMediaUnMuteButton: + return IDS_AX_MEDIA_UNMUTE_BUTTON; + case WebLocalizedString::AXMediaPlayButton: + return IDS_AX_MEDIA_PLAY_BUTTON; + case WebLocalizedString::AXMediaPauseButton: + return IDS_AX_MEDIA_PAUSE_BUTTON; + case WebLocalizedString::AXMediaSlider: + return IDS_AX_MEDIA_SLIDER; + case WebLocalizedString::AXMediaSliderThumb: + return IDS_AX_MEDIA_SLIDER_THUMB; + case WebLocalizedString::AXMediaCurrentTimeDisplay: + return IDS_AX_MEDIA_CURRENT_TIME_DISPLAY; + case WebLocalizedString::AXMediaTimeRemainingDisplay: + return IDS_AX_MEDIA_TIME_REMAINING_DISPLAY; + case WebLocalizedString::AXMediaStatusDisplay: + return IDS_AX_MEDIA_STATUS_DISPLAY; + case WebLocalizedString::AXMediaEnterFullscreenButton: + return IDS_AX_MEDIA_ENTER_FULL_SCREEN_BUTTON; + case WebLocalizedString::AXMediaExitFullscreenButton: + return IDS_AX_MEDIA_EXIT_FULL_SCREEN_BUTTON; + case WebLocalizedString::AXMediaShowClosedCaptionsButton: + return IDS_AX_MEDIA_SHOW_CLOSED_CAPTIONS_BUTTON; + case WebLocalizedString::AXMediaHideClosedCaptionsButton: + return IDS_AX_MEDIA_HIDE_CLOSED_CAPTIONS_BUTTON; + case WebLocalizedString::AXMediaAudioElementHelp: + return IDS_AX_MEDIA_AUDIO_ELEMENT_HELP; + case WebLocalizedString::AXMediaVideoElementHelp: + return IDS_AX_MEDIA_VIDEO_ELEMENT_HELP; + case WebLocalizedString::AXMediaMuteButtonHelp: + return IDS_AX_MEDIA_MUTE_BUTTON_HELP; + case WebLocalizedString::AXMediaUnMuteButtonHelp: + return IDS_AX_MEDIA_UNMUTE_BUTTON_HELP; + case WebLocalizedString::AXMediaPlayButtonHelp: + return IDS_AX_MEDIA_PLAY_BUTTON_HELP; + case WebLocalizedString::AXMediaPauseButtonHelp: + return IDS_AX_MEDIA_PAUSE_BUTTON_HELP; + case WebLocalizedString::AXMediaSliderHelp: + return IDS_AX_MEDIA_SLIDER_HELP; + case WebLocalizedString::AXMediaSliderThumbHelp: + return IDS_AX_MEDIA_SLIDER_THUMB_HELP; + case WebLocalizedString::AXMediaCurrentTimeDisplayHelp: + return IDS_AX_MEDIA_CURRENT_TIME_DISPLAY_HELP; + case WebLocalizedString::AXMediaTimeRemainingDisplayHelp: + return IDS_AX_MEDIA_TIME_REMAINING_DISPLAY_HELP; + case WebLocalizedString::AXMediaStatusDisplayHelp: + return IDS_AX_MEDIA_STATUS_DISPLAY_HELP; + case WebLocalizedString::AXMediaEnterFullscreenButtonHelp: + return IDS_AX_MEDIA_ENTER_FULL_SCREEN_BUTTON_HELP; + case WebLocalizedString::AXMediaExitFullscreenButtonHelp: + return IDS_AX_MEDIA_EXIT_FULL_SCREEN_BUTTON_HELP; + case WebLocalizedString::AXMediaShowClosedCaptionsButtonHelp: + return IDS_AX_MEDIA_SHOW_CLOSED_CAPTIONS_BUTTON_HELP; + case WebLocalizedString::AXMediaHideClosedCaptionsButtonHelp: + return IDS_AX_MEDIA_HIDE_CLOSED_CAPTIONS_BUTTON_HELP; + case WebLocalizedString::AXMillisecondFieldText: + return IDS_AX_MILLISECOND_FIELD_TEXT; + case WebLocalizedString::AXMinuteFieldText: + return IDS_AX_MINUTE_FIELD_TEXT; + case WebLocalizedString::AXMonthFieldText: + return IDS_AX_MONTH_FIELD_TEXT; + case WebLocalizedString::AXRadioButtonActionVerb: + return IDS_AX_RADIO_BUTTON_ACTION_VERB; + case WebLocalizedString::AXSecondFieldText: + return IDS_AX_SECOND_FIELD_TEXT; + case WebLocalizedString::AXTextFieldActionVerb: + return IDS_AX_TEXT_FIELD_ACTION_VERB; + case WebLocalizedString::AXUncheckedCheckBoxActionVerb: + return IDS_AX_UNCHECKED_CHECK_BOX_ACTION_VERB; + case WebLocalizedString::AXWebAreaText: + return IDS_AX_ROLE_WEB_AREA; + case WebLocalizedString::AXWeekOfYearFieldText: + return IDS_AX_WEEK_OF_YEAR_FIELD_TEXT; + case WebLocalizedString::AXYearFieldText: + return IDS_AX_YEAR_FIELD_TEXT; + case WebLocalizedString::CalendarClear: + return IDS_FORM_CALENDAR_CLEAR; + case WebLocalizedString::CalendarToday: + return IDS_FORM_CALENDAR_TODAY; + case WebLocalizedString::DateFormatDayInMonthLabel: + return IDS_FORM_DATE_FORMAT_DAY_IN_MONTH; + case WebLocalizedString::DateFormatMonthLabel: + return IDS_FORM_DATE_FORMAT_MONTH; + case WebLocalizedString::DateFormatYearLabel: + return IDS_FORM_DATE_FORMAT_YEAR; + case WebLocalizedString::DetailsLabel: + return IDS_DETAILS_WITHOUT_SUMMARY_LABEL; + case WebLocalizedString::FileButtonChooseFileLabel: + return IDS_FORM_FILE_BUTTON_LABEL; + case WebLocalizedString::FileButtonChooseMultipleFilesLabel: + return IDS_FORM_MULTIPLE_FILES_BUTTON_LABEL; + case WebLocalizedString::FileButtonNoFileSelectedLabel: + return IDS_FORM_FILE_NO_FILE_LABEL; + case WebLocalizedString::InputElementAltText: + return IDS_FORM_INPUT_ALT; + case WebLocalizedString::KeygenMenuHighGradeKeySize: + return IDS_KEYGEN_HIGH_GRADE_KEY; + case WebLocalizedString::KeygenMenuMediumGradeKeySize: + return IDS_KEYGEN_MED_GRADE_KEY; + case WebLocalizedString::MissingPluginText: + return IDS_PLUGIN_INITIALIZATION_ERROR; + case WebLocalizedString::MultipleFileUploadText: + return IDS_FORM_FILE_MULTIPLE_UPLOAD; + case WebLocalizedString::OtherColorLabel: + return IDS_FORM_OTHER_COLOR_LABEL; + case WebLocalizedString::OtherDateLabel: + return IDS_FORM_OTHER_DATE_LABEL; + case WebLocalizedString::OtherMonthLabel: + return IDS_FORM_OTHER_MONTH_LABEL; + case WebLocalizedString::OtherTimeLabel: + return IDS_FORM_OTHER_TIME_LABEL; + case WebLocalizedString::OtherWeekLabel: + return IDS_FORM_OTHER_WEEK_LABEL; + case WebLocalizedString::PlaceholderForDayOfMonthField: + return IDS_FORM_PLACEHOLDER_FOR_DAY_OF_MONTH_FIELD; + case WebLocalizedString::PlaceholderForMonthField: + return IDS_FORM_PLACEHOLDER_FOR_MONTH_FIELD; + case WebLocalizedString::PlaceholderForYearField: + return IDS_FORM_PLACEHOLDER_FOR_YEAR_FIELD; + case WebLocalizedString::ResetButtonDefaultLabel: + return IDS_FORM_RESET_LABEL; + case WebLocalizedString::SearchableIndexIntroduction: + return IDS_SEARCHABLE_INDEX_INTRO; + case WebLocalizedString::SearchMenuClearRecentSearchesText: + return IDS_RECENT_SEARCHES_CLEAR; + case WebLocalizedString::SearchMenuNoRecentSearchesText: + return IDS_RECENT_SEARCHES_NONE; + case WebLocalizedString::SearchMenuRecentSearchesText: + return IDS_RECENT_SEARCHES; + case WebLocalizedString::SubmitButtonDefaultLabel: + return IDS_FORM_SUBMIT_LABEL; + case WebLocalizedString::ThisMonthButtonLabel: + return IDS_FORM_THIS_MONTH_LABEL; + case WebLocalizedString::ThisWeekButtonLabel: + return IDS_FORM_THIS_WEEK_LABEL; + case WebLocalizedString::ValidationBadInputForDateTime: + return IDS_FORM_VALIDATION_BAD_INPUT_DATETIME; + case WebLocalizedString::ValidationBadInputForNumber: + return IDS_FORM_VALIDATION_BAD_INPUT_NUMBER; + case WebLocalizedString::ValidationPatternMismatch: + return IDS_FORM_VALIDATION_PATTERN_MISMATCH; + case WebLocalizedString::ValidationRangeOverflow: + return IDS_FORM_VALIDATION_RANGE_OVERFLOW; + case WebLocalizedString::ValidationRangeOverflowDateTime: + return IDS_FORM_VALIDATION_RANGE_OVERFLOW_DATETIME; + case WebLocalizedString::ValidationRangeUnderflow: + return IDS_FORM_VALIDATION_RANGE_UNDERFLOW; + case WebLocalizedString::ValidationRangeUnderflowDateTime: + return IDS_FORM_VALIDATION_RANGE_UNDERFLOW_DATETIME; + case WebLocalizedString::ValidationStepMismatch: + return IDS_FORM_VALIDATION_STEP_MISMATCH; + case WebLocalizedString::ValidationStepMismatchCloseToLimit: + return IDS_FORM_VALIDATION_STEP_MISMATCH_CLOSE_TO_LIMIT; + case WebLocalizedString::ValidationTooLong: + return IDS_FORM_VALIDATION_TOO_LONG; + case WebLocalizedString::ValidationTypeMismatch: + return IDS_FORM_VALIDATION_TYPE_MISMATCH; + case WebLocalizedString::ValidationTypeMismatchForEmail: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL; + case WebLocalizedString::ValidationTypeMismatchForEmailEmpty: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY; + case WebLocalizedString::ValidationTypeMismatchForEmailEmptyDomain: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY_DOMAIN; + case WebLocalizedString::ValidationTypeMismatchForEmailEmptyLocal: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY_LOCAL; + case WebLocalizedString::ValidationTypeMismatchForEmailInvalidDomain: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_DOMAIN; + case WebLocalizedString::ValidationTypeMismatchForEmailInvalidDots: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_DOTS; + case WebLocalizedString::ValidationTypeMismatchForEmailInvalidLocal: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_LOCAL; + case WebLocalizedString::ValidationTypeMismatchForEmailNoAtSign: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_NO_AT_SIGN; + case WebLocalizedString::ValidationTypeMismatchForMultipleEmail: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_MULTIPLE_EMAIL; + case WebLocalizedString::ValidationTypeMismatchForURL: + return IDS_FORM_VALIDATION_TYPE_MISMATCH_URL; + case WebLocalizedString::ValidationValueMissing: + return IDS_FORM_VALIDATION_VALUE_MISSING; + case WebLocalizedString::ValidationValueMissingForCheckbox: + return IDS_FORM_VALIDATION_VALUE_MISSING_CHECKBOX; + case WebLocalizedString::ValidationValueMissingForFile: + return IDS_FORM_VALIDATION_VALUE_MISSING_FILE; + case WebLocalizedString::ValidationValueMissingForMultipleFile: + return IDS_FORM_VALIDATION_VALUE_MISSING_MULTIPLE_FILE; + case WebLocalizedString::ValidationValueMissingForRadio: + return IDS_FORM_VALIDATION_VALUE_MISSING_RADIO; + case WebLocalizedString::ValidationValueMissingForSelect: + return IDS_FORM_VALIDATION_VALUE_MISSING_SELECT; + case WebLocalizedString::WeekFormatTemplate: + return IDS_FORM_INPUT_WEEK_TEMPLATE; + case WebLocalizedString::WeekNumberLabel: + return IDS_FORM_WEEK_NUMBER_LABEL; + // This "default:" line exists to avoid compile warnings about enum + // coverage when we add a new symbol to WebLocalizedString.h in WebKit. + // After a planned WebKit patch is landed, we need to add a case statement + // for the added symbol here. + default: + break; + } + return -1; +} + +WebKitPlatformSupportImpl::WebKitPlatformSupportImpl() + : main_loop_(base::MessageLoop::current()), + shared_timer_func_(NULL), + shared_timer_fire_time_(0.0), + shared_timer_fire_time_was_set_while_suspended_(false), + shared_timer_suspended_(0) {} + +WebKitPlatformSupportImpl::~WebKitPlatformSupportImpl() { +} + +WebURLLoader* WebKitPlatformSupportImpl::createURLLoader() { + return new WebURLLoaderImpl(this); +} + +WebSocketStreamHandle* WebKitPlatformSupportImpl::createSocketStreamHandle() { + return new WebSocketStreamHandleImpl(this); +} + +WebString WebKitPlatformSupportImpl::userAgent(const WebURL& url) { + return WebString::fromUTF8(webkit_glue::GetUserAgent(url)); +} + +WebData WebKitPlatformSupportImpl::parseDataURL( + const WebURL& url, + WebString& mimetype_out, + WebString& charset_out) { + std::string mime_type, char_set, data; + if (net::DataURL::Parse(url, &mime_type, &char_set, &data) + && net::IsSupportedMimeType(mime_type)) { + mimetype_out = WebString::fromUTF8(mime_type); + charset_out = WebString::fromUTF8(char_set); + return data; + } + return WebData(); +} + +WebURLError WebKitPlatformSupportImpl::cancelledError( + const WebURL& unreachableURL) const { + return WebURLLoaderImpl::CreateError(unreachableURL, false, net::ERR_ABORTED); +} + +void WebKitPlatformSupportImpl::decrementStatsCounter(const char* name) { + base::StatsCounter(name).Decrement(); +} + +void WebKitPlatformSupportImpl::incrementStatsCounter(const char* name) { + base::StatsCounter(name).Increment(); +} + +void WebKitPlatformSupportImpl::histogramCustomCounts( + const char* name, int sample, int min, int max, int bucket_count) { + // Copied from histogram macro, but without the static variable caching + // the histogram because name is dynamic. + base::HistogramBase* counter = + base::Histogram::FactoryGet(name, min, max, bucket_count, + base::HistogramBase::kUmaTargetedHistogramFlag); + DCHECK_EQ(name, counter->histogram_name()); + counter->Add(sample); +} + +void WebKitPlatformSupportImpl::histogramEnumeration( + const char* name, int sample, int boundary_value) { + // Copied from histogram macro, but without the static variable caching + // the histogram because name is dynamic. + base::HistogramBase* counter = + base::LinearHistogram::FactoryGet(name, 1, boundary_value, + boundary_value + 1, base::HistogramBase::kUmaTargetedHistogramFlag); + DCHECK_EQ(name, counter->histogram_name()); + counter->Add(sample); +} + +void WebKitPlatformSupportImpl::histogramSparse(const char* name, int sample) { + // For sparse histograms, we can use the macro, as it does not incorporate a + // static. + UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample); +} + +const unsigned char* WebKitPlatformSupportImpl::getTraceCategoryEnabledFlag( + const char* category_group) { + return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); +} + +long* WebKitPlatformSupportImpl::getTraceSamplingState( + const unsigned thread_bucket) { + switch (thread_bucket) { + case 0: + return reinterpret_cast<long*>(&TRACE_EVENT_API_THREAD_BUCKET(0)); + case 1: + return reinterpret_cast<long*>(&TRACE_EVENT_API_THREAD_BUCKET(1)); + case 2: + return reinterpret_cast<long*>(&TRACE_EVENT_API_THREAD_BUCKET(2)); + default: + NOTREACHED() << "Unknown thread bucket type."; + } + return NULL; +} + +COMPILE_ASSERT( + sizeof(blink::Platform::TraceEventHandle) == + sizeof(base::debug::TraceEventHandle), + TraceEventHandle_types_must_be_same_size); + +blink::Platform::TraceEventHandle WebKitPlatformSupportImpl::addTraceEvent( + char phase, + const unsigned char* category_group_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags) { + base::debug::TraceEventHandle handle = TRACE_EVENT_API_ADD_TRACE_EVENT( + phase, category_group_enabled, name, id, + num_args, arg_names, arg_types, arg_values, NULL, flags); + blink::Platform::TraceEventHandle result; + memcpy(&result, &handle, sizeof(result)); + return result; +} + +void WebKitPlatformSupportImpl::updateTraceEventDuration( + const unsigned char* category_group_enabled, + const char* name, + TraceEventHandle handle) { + base::debug::TraceEventHandle traceEventHandle; + memcpy(&traceEventHandle, &handle, sizeof(handle)); + TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION( + category_group_enabled, name, traceEventHandle); +} + +namespace { + +WebData loadAudioSpatializationResource(WebKitPlatformSupportImpl* platform, + const char* name) { +#ifdef IDR_AUDIO_SPATIALIZATION_COMPOSITE + if (!strcmp(name, "Composite")) { + base::StringPiece resource = + platform->GetDataResource(IDR_AUDIO_SPATIALIZATION_COMPOSITE, + ui::SCALE_FACTOR_NONE); + return WebData(resource.data(), resource.size()); + } +#endif + +#ifdef IDR_AUDIO_SPATIALIZATION_T000_P000 + const size_t kExpectedSpatializationNameLength = 31; + if (strlen(name) != kExpectedSpatializationNameLength) { + return WebData(); + } + + // Extract the azimuth and elevation from the resource name. + int azimuth = 0; + int elevation = 0; + int values_parsed = + sscanf(name, "IRC_Composite_C_R0195_T%3d_P%3d", &azimuth, &elevation); + if (values_parsed != 2) { + return WebData(); + } + + // The resource index values go through the elevations first, then azimuths. + const int kAngleSpacing = 15; + + // 0 <= elevation <= 90 (or 315 <= elevation <= 345) + // in increments of 15 degrees. + int elevation_index = + elevation <= 90 ? elevation / kAngleSpacing : + 7 + (elevation - 315) / kAngleSpacing; + bool is_elevation_index_good = 0 <= elevation_index && elevation_index < 10; + + // 0 <= azimuth < 360 in increments of 15 degrees. + int azimuth_index = azimuth / kAngleSpacing; + bool is_azimuth_index_good = 0 <= azimuth_index && azimuth_index < 24; + + const int kNumberOfElevations = 10; + const int kNumberOfAudioResources = 240; + int resource_index = kNumberOfElevations * azimuth_index + elevation_index; + bool is_resource_index_good = 0 <= resource_index && + resource_index < kNumberOfAudioResources; + + if (is_azimuth_index_good && is_elevation_index_good && + is_resource_index_good) { + const int kFirstAudioResourceIndex = IDR_AUDIO_SPATIALIZATION_T000_P000; + base::StringPiece resource = + platform->GetDataResource(kFirstAudioResourceIndex + resource_index, + ui::SCALE_FACTOR_NONE); + return WebData(resource.data(), resource.size()); + } +#endif // IDR_AUDIO_SPATIALIZATION_T000_P000 + + NOTREACHED(); + return WebData(); +} + +struct DataResource { + const char* name; + int id; + ui::ScaleFactor scale_factor; +}; + +const DataResource kDataResources[] = { + { "missingImage", IDR_BROKENIMAGE, ui::SCALE_FACTOR_100P }, + { "missingImage@2x", IDR_BROKENIMAGE, ui::SCALE_FACTOR_200P }, + { "mediaplayerPause", IDR_MEDIAPLAYER_PAUSE_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerPauseHover", + IDR_MEDIAPLAYER_PAUSE_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerPauseDown", + IDR_MEDIAPLAYER_PAUSE_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerPlay", IDR_MEDIAPLAYER_PLAY_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerPlayHover", + IDR_MEDIAPLAYER_PLAY_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerPlayDown", + IDR_MEDIAPLAYER_PLAY_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerPlayDisabled", + IDR_MEDIAPLAYER_PLAY_BUTTON_DISABLED, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel3", + IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel3Hover", + IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel3Down", + IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel2", + IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel2Hover", + IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel2Down", + IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel1", + IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel1Hover", + IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel1Down", + IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel0", + IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel0Hover", + IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundLevel0Down", + IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerSoundDisabled", + IDR_MEDIAPLAYER_SOUND_DISABLED, ui::SCALE_FACTOR_100P }, + { "mediaplayerSliderThumb", + IDR_MEDIAPLAYER_SLIDER_THUMB, ui::SCALE_FACTOR_100P }, + { "mediaplayerSliderThumbHover", + IDR_MEDIAPLAYER_SLIDER_THUMB_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerSliderThumbDown", + IDR_MEDIAPLAYER_SLIDER_THUMB_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerVolumeSliderThumb", + IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB, ui::SCALE_FACTOR_100P }, + { "mediaplayerVolumeSliderThumbHover", + IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerVolumeSliderThumbDown", + IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerVolumeSliderThumbDisabled", + IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DISABLED, ui::SCALE_FACTOR_100P }, + { "mediaplayerClosedCaption", + IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerClosedCaptionHover", + IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerClosedCaptionDown", + IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerClosedCaptionDisabled", + IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DISABLED, ui::SCALE_FACTOR_100P }, + { "mediaplayerFullscreen", + IDR_MEDIAPLAYER_FULLSCREEN_BUTTON, ui::SCALE_FACTOR_100P }, + { "mediaplayerFullscreenHover", + IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_HOVER, ui::SCALE_FACTOR_100P }, + { "mediaplayerFullscreenDown", + IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DOWN, ui::SCALE_FACTOR_100P }, + { "mediaplayerFullscreenDisabled", + IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DISABLED, ui::SCALE_FACTOR_100P }, +#if defined(OS_ANDROID) + { "mediaplayerOverlayPlay", + IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON, ui::SCALE_FACTOR_100P }, +#endif +#if defined(OS_MACOSX) + { "overhangPattern", IDR_OVERHANG_PATTERN, ui::SCALE_FACTOR_100P }, + { "overhangShadow", IDR_OVERHANG_SHADOW, ui::SCALE_FACTOR_100P }, +#endif + { "panIcon", IDR_PAN_SCROLL_ICON, ui::SCALE_FACTOR_100P }, + { "searchCancel", IDR_SEARCH_CANCEL, ui::SCALE_FACTOR_100P }, + { "searchCancelPressed", IDR_SEARCH_CANCEL_PRESSED, ui::SCALE_FACTOR_100P }, + { "searchMagnifier", IDR_SEARCH_MAGNIFIER, ui::SCALE_FACTOR_100P }, + { "searchMagnifierResults", + IDR_SEARCH_MAGNIFIER_RESULTS, ui::SCALE_FACTOR_100P }, + { "textAreaResizeCorner", IDR_TEXTAREA_RESIZER, ui::SCALE_FACTOR_100P }, + { "textAreaResizeCorner@2x", IDR_TEXTAREA_RESIZER, ui::SCALE_FACTOR_200P }, + { "inputSpeech", IDR_INPUT_SPEECH, ui::SCALE_FACTOR_100P }, + { "inputSpeechRecording", IDR_INPUT_SPEECH_RECORDING, ui::SCALE_FACTOR_100P }, + { "inputSpeechWaiting", IDR_INPUT_SPEECH_WAITING, ui::SCALE_FACTOR_100P }, + { "americanExpressCC", IDR_AUTOFILL_CC_AMEX, ui::SCALE_FACTOR_100P }, + { "dinersCC", IDR_AUTOFILL_CC_DINERS, ui::SCALE_FACTOR_100P }, + { "discoverCC", IDR_AUTOFILL_CC_DISCOVER, ui::SCALE_FACTOR_100P }, + { "genericCC", IDR_AUTOFILL_CC_GENERIC, ui::SCALE_FACTOR_100P }, + { "jcbCC", IDR_AUTOFILL_CC_JCB, ui::SCALE_FACTOR_100P }, + { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD, ui::SCALE_FACTOR_100P }, + { "visaCC", IDR_AUTOFILL_CC_VISA, ui::SCALE_FACTOR_100P }, + { "generatePassword", IDR_PASSWORD_GENERATION_ICON, ui::SCALE_FACTOR_100P }, + { "generatePasswordHover", + IDR_PASSWORD_GENERATION_ICON_HOVER, ui::SCALE_FACTOR_100P }, + { "syntheticTouchCursor", + IDR_SYNTHETIC_TOUCH_CURSOR, ui::SCALE_FACTOR_100P }, +}; + +} // namespace + +WebData WebKitPlatformSupportImpl::loadResource(const char* name) { + // Some clients will call into this method with an empty |name| when they have + // optional resources. For example, the PopupMenuChromium code can have icons + // for some Autofill items but not for others. + if (!strlen(name)) + return WebData(); + + // Check the name prefix to see if it's an audio resource. + if (StartsWithASCII(name, "IRC_Composite", true) || + StartsWithASCII(name, "Composite", true)) + return loadAudioSpatializationResource(this, name); + + // TODO(flackr): We should use a better than linear search here, a trie would + // be ideal. + for (size_t i = 0; i < arraysize(kDataResources); ++i) { + if (!strcmp(name, kDataResources[i].name)) { + base::StringPiece resource = + GetDataResource(kDataResources[i].id, + kDataResources[i].scale_factor); + return WebData(resource.data(), resource.size()); + } + } + + NOTREACHED() << "Unknown image resource " << name; + return WebData(); +} + +WebString WebKitPlatformSupportImpl::queryLocalizedString( + WebLocalizedString::Name name) { + int message_id = ToMessageID(name); + if (message_id < 0) + return WebString(); + return GetLocalizedString(message_id); +} + +WebString WebKitPlatformSupportImpl::queryLocalizedString( + WebLocalizedString::Name name, int numeric_value) { + return queryLocalizedString(name, base::IntToString16(numeric_value)); +} + +WebString WebKitPlatformSupportImpl::queryLocalizedString( + WebLocalizedString::Name name, const WebString& value) { + int message_id = ToMessageID(name); + if (message_id < 0) + return WebString(); + return ReplaceStringPlaceholders(GetLocalizedString(message_id), value, NULL); +} + +WebString WebKitPlatformSupportImpl::queryLocalizedString( + WebLocalizedString::Name name, + const WebString& value1, + const WebString& value2) { + int message_id = ToMessageID(name); + if (message_id < 0) + return WebString(); + std::vector<base::string16> values; + values.reserve(2); + values.push_back(value1); + values.push_back(value2); + return ReplaceStringPlaceholders( + GetLocalizedString(message_id), values, NULL); +} + +double WebKitPlatformSupportImpl::currentTime() { + return base::Time::Now().ToDoubleT(); +} + +double WebKitPlatformSupportImpl::monotonicallyIncreasingTime() { + return base::TimeTicks::Now().ToInternalValue() / + static_cast<double>(base::Time::kMicrosecondsPerSecond); +} + +void WebKitPlatformSupportImpl::cryptographicallyRandomValues( + unsigned char* buffer, size_t length) { + base::RandBytes(buffer, length); +} + +void WebKitPlatformSupportImpl::setSharedTimerFiredFunction(void (*func)()) { + shared_timer_func_ = func; +} + +void WebKitPlatformSupportImpl::setSharedTimerFireInterval( + double interval_seconds) { + shared_timer_fire_time_ = interval_seconds + monotonicallyIncreasingTime(); + if (shared_timer_suspended_) { + shared_timer_fire_time_was_set_while_suspended_ = true; + return; + } + + // By converting between double and int64 representation, we run the risk + // of losing precision due to rounding errors. Performing computations in + // microseconds reduces this risk somewhat. But there still is the potential + // of us computing a fire time for the timer that is shorter than what we + // need. + // As the event loop will check event deadlines prior to actually firing + // them, there is a risk of needlessly rescheduling events and of + // needlessly looping if sleep times are too short even by small amounts. + // This results in measurable performance degradation unless we use ceil() to + // always round up the sleep times. + int64 interval = static_cast<int64>( + ceil(interval_seconds * base::Time::kMillisecondsPerSecond) + * base::Time::kMicrosecondsPerMillisecond); + + if (interval < 0) + interval = 0; + + shared_timer_.Stop(); + shared_timer_.Start(FROM_HERE, base::TimeDelta::FromMicroseconds(interval), + this, &WebKitPlatformSupportImpl::DoTimeout); + OnStartSharedTimer(base::TimeDelta::FromMicroseconds(interval)); +} + +void WebKitPlatformSupportImpl::stopSharedTimer() { + shared_timer_.Stop(); +} + +void WebKitPlatformSupportImpl::callOnMainThread( + void (*func)(void*), void* context) { + main_loop_->PostTask(FROM_HERE, base::Bind(func, context)); +} + +base::PlatformFile WebKitPlatformSupportImpl::databaseOpenFile( + const blink::WebString& vfs_file_name, int desired_flags) { + return base::kInvalidPlatformFileValue; +} + +int WebKitPlatformSupportImpl::databaseDeleteFile( + const blink::WebString& vfs_file_name, bool sync_dir) { + return -1; +} + +long WebKitPlatformSupportImpl::databaseGetFileAttributes( + const blink::WebString& vfs_file_name) { + return 0; +} + +long long WebKitPlatformSupportImpl::databaseGetFileSize( + const blink::WebString& vfs_file_name) { + return 0; +} + +long long WebKitPlatformSupportImpl::databaseGetSpaceAvailableForOrigin( + const blink::WebString& origin_identifier) { + return 0; +} + +blink::WebString WebKitPlatformSupportImpl::signedPublicKeyAndChallengeString( + unsigned key_size_index, + const blink::WebString& challenge, + const blink::WebURL& url) { + return blink::WebString(""); +} + +static scoped_ptr<base::ProcessMetrics> CurrentProcessMetrics() { + using base::ProcessMetrics; +#if defined(OS_MACOSX) + return scoped_ptr<ProcessMetrics>( + // The default port provider is sufficient to get data for the current + // process. + ProcessMetrics::CreateProcessMetrics(base::GetCurrentProcessHandle(), + NULL)); +#else + return scoped_ptr<ProcessMetrics>( + ProcessMetrics::CreateProcessMetrics(base::GetCurrentProcessHandle())); +#endif +} + +static size_t getMemoryUsageMB(bool bypass_cache) { + size_t current_mem_usage = 0; + MemoryUsageCache* mem_usage_cache_singleton = MemoryUsageCache::GetInstance(); + if (!bypass_cache && + mem_usage_cache_singleton->IsCachedValueValid(¤t_mem_usage)) + return current_mem_usage; + + current_mem_usage = MemoryUsageKB() >> 10; + mem_usage_cache_singleton->SetMemoryValue(current_mem_usage); + return current_mem_usage; +} + +size_t WebKitPlatformSupportImpl::memoryUsageMB() { + return getMemoryUsageMB(false); +} + +size_t WebKitPlatformSupportImpl::actualMemoryUsageMB() { + return getMemoryUsageMB(true); +} + +size_t WebKitPlatformSupportImpl::physicalMemoryMB() { + return static_cast<size_t>(base::SysInfo::AmountOfPhysicalMemoryMB()); +} + +size_t WebKitPlatformSupportImpl::numberOfProcessors() { + return static_cast<size_t>(base::SysInfo::NumberOfProcessors()); +} + +void WebKitPlatformSupportImpl::startHeapProfiling( + const blink::WebString& prefix) { + // FIXME(morrita): Make this built on windows. +#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN) + HeapProfilerStart(prefix.utf8().data()); +#endif +} + +void WebKitPlatformSupportImpl::stopHeapProfiling() { +#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN) + HeapProfilerStop(); +#endif +} + +void WebKitPlatformSupportImpl::dumpHeapProfiling( + const blink::WebString& reason) { +#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN) + HeapProfilerDump(reason.utf8().data()); +#endif +} + +WebString WebKitPlatformSupportImpl::getHeapProfile() { +#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN) + char* data = GetHeapProfile(); + WebString result = WebString::fromUTF8(std::string(data)); + free(data); + return result; +#else + return WebString(); +#endif +} + +bool WebKitPlatformSupportImpl::processMemorySizesInBytes( + size_t* private_bytes, + size_t* shared_bytes) { + return CurrentProcessMetrics()->GetMemoryBytes(private_bytes, shared_bytes); +} + +bool WebKitPlatformSupportImpl::memoryAllocatorWasteInBytes(size_t* size) { + return base::allocator::GetAllocatorWasteSize(size); +} + +size_t WebKitPlatformSupportImpl::maxDecodedImageBytes() { +#if defined(OS_ANDROID) + if (base::android::SysUtils::IsLowEndDevice()) { + // Limit image decoded size to 3M pixels on low end devices. + // 4 is maximum number of bytes per pixel. + return 3 * 1024 * 1024 * 4; + } + // For other devices, limit decoded image size based on the amount of physical + // memory. For a device with 2GB physical memory the limit is 16M pixels. + return base::SysInfo::AmountOfPhysicalMemory() / 32; +#else + return noDecodedImageByteLimit; +#endif +} + +void WebKitPlatformSupportImpl::SuspendSharedTimer() { + ++shared_timer_suspended_; +} + +void WebKitPlatformSupportImpl::ResumeSharedTimer() { + // The shared timer may have fired or been adjusted while we were suspended. + if (--shared_timer_suspended_ == 0 && + (!shared_timer_.IsRunning() || + shared_timer_fire_time_was_set_while_suspended_)) { + shared_timer_fire_time_was_set_while_suspended_ = false; + setSharedTimerFireInterval( + shared_timer_fire_time_ - monotonicallyIncreasingTime()); + } +} + +} // namespace webkit_glue diff --git a/webkit/child/webkitplatformsupport_impl.h b/webkit/child/webkitplatformsupport_impl.h new file mode 100644 index 0000000..6af5b78 --- /dev/null +++ b/webkit/child/webkitplatformsupport_impl.h @@ -0,0 +1,156 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_CHILD_WEBKITPLATFORMSUPPORT_IMPL_H_ +#define WEBKIT_CHILD_WEBKITPLATFORMSUPPORT_IMPL_H_ + +#include "base/compiler_specific.h" +#include "base/debug/trace_event.h" +#include "base/platform_file.h" +#include "base/timer/timer.h" +#include "third_party/WebKit/public/platform/Platform.h" +#include "third_party/WebKit/public/platform/WebURLError.h" +#include "ui/base/layout.h" +#include "webkit/child/resource_loader_bridge.h" +#include "webkit/child/webkit_child_export.h" + +namespace base { +class MessageLoop; +} + +namespace blink { +class WebSocketStreamHandle; +} + +namespace webkit_glue { + +class WebSocketStreamHandleDelegate; +class WebSocketStreamHandleBridge; + +class WEBKIT_CHILD_EXPORT WebKitPlatformSupportImpl : + NON_EXPORTED_BASE(public blink::Platform) { + public: + WebKitPlatformSupportImpl(); + virtual ~WebKitPlatformSupportImpl(); + + // Platform methods (partial implementation): + virtual base::PlatformFile databaseOpenFile( + const blink::WebString& vfs_file_name, int desired_flags); + virtual int databaseDeleteFile(const blink::WebString& vfs_file_name, + bool sync_dir); + virtual long databaseGetFileAttributes( + const blink::WebString& vfs_file_name); + virtual long long databaseGetFileSize(const blink::WebString& vfs_file_name); + virtual long long databaseGetSpaceAvailableForOrigin( + const blink::WebString& origin_identifier); + virtual blink::WebString signedPublicKeyAndChallengeString( + unsigned key_size_index, const blink::WebString& challenge, + const blink::WebURL& url); + virtual size_t memoryUsageMB(); + virtual size_t actualMemoryUsageMB(); + virtual size_t physicalMemoryMB(); + virtual size_t numberOfProcessors(); + + virtual void startHeapProfiling(const blink::WebString& prefix); + virtual void stopHeapProfiling() OVERRIDE; + virtual void dumpHeapProfiling(const blink::WebString& reason); + virtual blink::WebString getHeapProfile() OVERRIDE; + + virtual bool processMemorySizesInBytes(size_t* private_bytes, + size_t* shared_bytes); + virtual bool memoryAllocatorWasteInBytes(size_t* size); + virtual size_t maxDecodedImageBytes() OVERRIDE; + virtual blink::WebURLLoader* createURLLoader(); + virtual blink::WebSocketStreamHandle* createSocketStreamHandle(); + virtual blink::WebString userAgent(const blink::WebURL& url); + virtual blink::WebData parseDataURL( + const blink::WebURL& url, blink::WebString& mimetype, + blink::WebString& charset); + virtual blink::WebURLError cancelledError(const blink::WebURL& url) const; + virtual void decrementStatsCounter(const char* name); + virtual void incrementStatsCounter(const char* name); + virtual void histogramCustomCounts( + const char* name, int sample, int min, int max, int bucket_count); + virtual void histogramEnumeration( + const char* name, int sample, int boundary_value); + virtual void histogramSparse(const char* name, int sample); + virtual const unsigned char* getTraceCategoryEnabledFlag( + const char* category_name); + virtual long* getTraceSamplingState(const unsigned thread_bucket); + virtual TraceEventHandle addTraceEvent( + char phase, + const unsigned char* category_group_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags); + virtual void updateTraceEventDuration( + const unsigned char* category_group_enabled, + const char* name, + TraceEventHandle); + virtual blink::WebData loadResource(const char* name); + virtual blink::WebString queryLocalizedString( + blink::WebLocalizedString::Name name); + virtual blink::WebString queryLocalizedString( + blink::WebLocalizedString::Name name, int numeric_value); + virtual blink::WebString queryLocalizedString( + blink::WebLocalizedString::Name name, const blink::WebString& value); + virtual blink::WebString queryLocalizedString( + blink::WebLocalizedString::Name name, + const blink::WebString& value1, const blink::WebString& value2); + virtual void suddenTerminationChanged(bool enabled) { } + virtual double currentTime(); + virtual double monotonicallyIncreasingTime(); + virtual void cryptographicallyRandomValues( + unsigned char* buffer, size_t length); + virtual void setSharedTimerFiredFunction(void (*func)()); + virtual void setSharedTimerFireInterval(double interval_seconds); + virtual void stopSharedTimer(); + virtual void callOnMainThread(void (*func)(void*), void* context); + + + // Embedder functions. The following are not implemented by the glue layer and + // need to be specialized by the embedder. + + // Gets a localized string given a message id. Returns an empty string if the + // message id is not found. + virtual base::string16 GetLocalizedString(int message_id) = 0; + + // Returns the raw data for a resource. This resource must have been + // specified as BINDATA in the relevant .rc file. + virtual base::StringPiece GetDataResource(int resource_id, + ui::ScaleFactor scale_factor) = 0; + + // Creates a ResourceLoaderBridge. + virtual ResourceLoaderBridge* CreateResourceLoader( + const ResourceLoaderBridge::RequestInfo& request_info) = 0; + // Creates a WebSocketStreamHandleBridge. + virtual WebSocketStreamHandleBridge* CreateWebSocketStreamBridge( + blink::WebSocketStreamHandle* handle, + WebSocketStreamHandleDelegate* delegate) = 0; + + void SuspendSharedTimer(); + void ResumeSharedTimer(); + virtual void OnStartSharedTimer(base::TimeDelta delay) {} + + private: + void DoTimeout() { + if (shared_timer_func_ && !shared_timer_suspended_) + shared_timer_func_(); + } + + base::MessageLoop* main_loop_; + base::OneShotTimer<WebKitPlatformSupportImpl> shared_timer_; + void (*shared_timer_func_)(); + double shared_timer_fire_time_; + bool shared_timer_fire_time_was_set_while_suspended_; + int shared_timer_suspended_; // counter +}; + +} // namespace webkit_glue + +#endif // WEBKIT_CHILD_WEBKITPLATFORMSUPPORT_IMPL_H_ diff --git a/webkit/child/websocketstreamhandle_bridge.h b/webkit/child/websocketstreamhandle_bridge.h new file mode 100644 index 0000000..f66afd2 --- /dev/null +++ b/webkit/child/websocketstreamhandle_bridge.h @@ -0,0 +1,37 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_BRIDGE_H_ +#define WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_BRIDGE_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" + +class GURL; + +namespace webkit_glue { + +class WebSocketStreamHandleBridge + : public base::RefCountedThreadSafe<WebSocketStreamHandleBridge> { + public: + virtual void Connect(const GURL& url) = 0; + + virtual bool Send(const std::vector<char>& data) = 0; + + virtual void Close() = 0; + + protected: + friend class base::RefCountedThreadSafe<WebSocketStreamHandleBridge>; + WebSocketStreamHandleBridge() {} + virtual ~WebSocketStreamHandleBridge() {} + + private: + DISALLOW_COPY_AND_ASSIGN(WebSocketStreamHandleBridge); +}; + +} // namespace webkit_glue + +#endif // WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_BRIDGE_H_ diff --git a/webkit/child/websocketstreamhandle_delegate.h b/webkit/child/websocketstreamhandle_delegate.h new file mode 100644 index 0000000..16d15a0 --- /dev/null +++ b/webkit/child/websocketstreamhandle_delegate.h @@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_DELEGATE_H_ +#define WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_DELEGATE_H_ + +#include "base/strings/string16.h" + +class GURL; + +namespace blink { +class WebSocketStreamHandle; +} + +namespace webkit_glue { + +class WebSocketStreamHandleDelegate { + public: + WebSocketStreamHandleDelegate() {} + + virtual void WillOpenStream(blink::WebSocketStreamHandle* handle, + const GURL& url) {} + virtual void WillSendData(blink::WebSocketStreamHandle* handle, + const char* data, int len) {} + + virtual void DidOpenStream(blink::WebSocketStreamHandle* handle, + int max_amount_send_allowed) {} + virtual void DidSendData(blink::WebSocketStreamHandle* handle, + int amount_sent) {} + virtual void DidReceiveData(blink::WebSocketStreamHandle* handle, + const char* data, int len) {} + virtual void DidClose(blink::WebSocketStreamHandle*) {} + virtual void DidFail(blink::WebSocketStreamHandle* handle, + int error_code, + const base::string16& error_msg) {} + + protected: + virtual ~WebSocketStreamHandleDelegate() {} +}; + +} // namespace webkit_glue + +#endif // WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_DELEGATE_H_ diff --git a/webkit/child/websocketstreamhandle_impl.cc b/webkit/child/websocketstreamhandle_impl.cc new file mode 100644 index 0000000..761749f --- /dev/null +++ b/webkit/child/websocketstreamhandle_impl.cc @@ -0,0 +1,197 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// An implementation of WebSocketStreamHandle. + +#include "webkit/child/websocketstreamhandle_impl.h" + +#include <vector> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string16.h" +#include "third_party/WebKit/public/platform/WebData.h" +#include "third_party/WebKit/public/platform/WebSocketStreamError.h" +#include "third_party/WebKit/public/platform/WebSocketStreamHandleClient.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "webkit/child/webkitplatformsupport_impl.h" +#include "webkit/child/websocketstreamhandle_bridge.h" +#include "webkit/child/websocketstreamhandle_delegate.h" + +using blink::WebData; +using blink::WebSocketStreamError; +using blink::WebSocketStreamHandle; +using blink::WebSocketStreamHandleClient; +using blink::WebURL; + +namespace webkit_glue { + +// WebSocketStreamHandleImpl::Context ----------------------------------------- + +class WebSocketStreamHandleImpl::Context + : public base::RefCounted<Context>, + public WebSocketStreamHandleDelegate { + public: + explicit Context(WebSocketStreamHandleImpl* handle); + + WebSocketStreamHandleClient* client() const { return client_; } + void set_client(WebSocketStreamHandleClient* client) { + client_ = client; + } + + void Connect(const WebURL& url, WebKitPlatformSupportImpl* platform); + bool Send(const WebData& data); + void Close(); + + // Must be called before |handle_| or |client_| is deleted. + // Once detached, it never calls |client_| back. + void Detach(); + + // WebSocketStreamHandleDelegate methods: + virtual void DidOpenStream(WebSocketStreamHandle*, int) OVERRIDE; + virtual void DidSendData(WebSocketStreamHandle*, int) OVERRIDE; + virtual void DidReceiveData(WebSocketStreamHandle*, + const char*, + int) OVERRIDE; + virtual void DidClose(WebSocketStreamHandle*) OVERRIDE; + virtual void DidFail(WebSocketStreamHandle*, + int, + const base::string16&) OVERRIDE; + + private: + friend class base::RefCounted<Context>; + virtual ~Context() { + DCHECK(!handle_); + DCHECK(!client_); + DCHECK(!bridge_.get()); + } + + WebSocketStreamHandleImpl* handle_; + WebSocketStreamHandleClient* client_; + // |bridge_| is alive from Connect to DidClose, so Context must be alive + // in the time period. + scoped_refptr<WebSocketStreamHandleBridge> bridge_; + + DISALLOW_COPY_AND_ASSIGN(Context); +}; + +WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle) + : handle_(handle), + client_(NULL) { +} + +void WebSocketStreamHandleImpl::Context::Connect( + const WebURL& url, + WebKitPlatformSupportImpl* platform) { + VLOG(1) << "Connect url=" << url; + DCHECK(!bridge_.get()); + bridge_ = platform->CreateWebSocketStreamBridge(handle_, this); + AddRef(); // Will be released by DidClose(). + bridge_->Connect(url); +} + +bool WebSocketStreamHandleImpl::Context::Send(const WebData& data) { + VLOG(1) << "Send data.size=" << data.size(); + DCHECK(bridge_.get()); + return bridge_->Send( + std::vector<char>(data.data(), data.data() + data.size())); +} + +void WebSocketStreamHandleImpl::Context::Close() { + VLOG(1) << "Close"; + if (bridge_.get()) + bridge_->Close(); +} + +void WebSocketStreamHandleImpl::Context::Detach() { + handle_ = NULL; + client_ = NULL; + // If Connect was called, |bridge_| is not NULL, so that this Context closes + // the |bridge_| here. Then |bridge_| will call back DidClose, and will + // be released by itself. + // Otherwise, |bridge_| is NULL. + if (bridge_.get()) + bridge_->Close(); +} + +void WebSocketStreamHandleImpl::Context::DidOpenStream( + WebSocketStreamHandle* web_handle, int max_amount_send_allowed) { + VLOG(1) << "DidOpen"; + if (client_) + client_->didOpenStream(handle_, max_amount_send_allowed); +} + +void WebSocketStreamHandleImpl::Context::DidSendData( + WebSocketStreamHandle* web_handle, int amount_sent) { + if (client_) + client_->didSendData(handle_, amount_sent); +} + +void WebSocketStreamHandleImpl::Context::DidReceiveData( + WebSocketStreamHandle* web_handle, const char* data, int size) { + if (client_) + client_->didReceiveData(handle_, WebData(data, size)); +} + +void WebSocketStreamHandleImpl::Context::DidClose( + WebSocketStreamHandle* web_handle) { + VLOG(1) << "DidClose"; + bridge_ = NULL; + WebSocketStreamHandleImpl* handle = handle_; + handle_ = NULL; + if (client_) { + WebSocketStreamHandleClient* client = client_; + client_ = NULL; + client->didClose(handle); + } + Release(); +} + +void WebSocketStreamHandleImpl::Context::DidFail( + WebSocketStreamHandle* web_handle, + int error_code, + const base::string16& error_msg) { + VLOG(1) << "DidFail"; + if (client_) { + client_->didFail( + handle_, + WebSocketStreamError(error_code, error_msg)); + } +} + +// WebSocketStreamHandleImpl ------------------------------------------------ + +WebSocketStreamHandleImpl::WebSocketStreamHandleImpl( + WebKitPlatformSupportImpl* platform) + : context_(new Context(this)), + platform_(platform) { +} + +WebSocketStreamHandleImpl::~WebSocketStreamHandleImpl() { + // We won't receive any events from |context_|. + // |context_| is ref counted, and will be released when it received + // DidClose. + context_->Detach(); +} + +void WebSocketStreamHandleImpl::connect( + const WebURL& url, WebSocketStreamHandleClient* client) { + VLOG(1) << "connect url=" << url; + DCHECK(!context_->client()); + context_->set_client(client); + + context_->Connect(url, platform_); +} + +bool WebSocketStreamHandleImpl::send(const WebData& data) { + return context_->Send(data); +} + +void WebSocketStreamHandleImpl::close() { + context_->Close(); +} + +} // namespace webkit_glue diff --git a/webkit/child/websocketstreamhandle_impl.h b/webkit/child/websocketstreamhandle_impl.h new file mode 100644 index 0000000..c2f7f31 --- /dev/null +++ b/webkit/child/websocketstreamhandle_impl.h @@ -0,0 +1,40 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_IMPL_H_ +#define WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_IMPL_H_ + +#include "base/memory/ref_counted.h" +#include "base/supports_user_data.h" +#include "third_party/WebKit/public/platform/WebSocketStreamHandle.h" + +namespace webkit_glue { + +class WebKitPlatformSupportImpl; + +class WebSocketStreamHandleImpl + : public base::SupportsUserData, + public blink::WebSocketStreamHandle { + public: + explicit WebSocketStreamHandleImpl(WebKitPlatformSupportImpl* platform); + virtual ~WebSocketStreamHandleImpl(); + + // WebSocketStreamHandle methods: + virtual void connect( + const blink::WebURL& url, + blink::WebSocketStreamHandleClient* client); + virtual bool send(const blink::WebData& data); + virtual void close(); + + private: + class Context; + scoped_refptr<Context> context_; + WebKitPlatformSupportImpl* platform_; + + DISALLOW_COPY_AND_ASSIGN(WebSocketStreamHandleImpl); +}; + +} // namespace webkit_glue + +#endif // WEBKIT_CHILD_WEBSOCKETSTREAMHANDLE_IMPL_H_ diff --git a/webkit/child/weburlloader_impl.cc b/webkit/child/weburlloader_impl.cc new file mode 100644 index 0000000..7e5a8ad --- /dev/null +++ b/webkit/child/weburlloader_impl.cc @@ -0,0 +1,871 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// An implementation of WebURLLoader in terms of ResourceLoaderBridge. + +#include "webkit/child/weburlloader_impl.h" + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/string_util.h" +#include "base/time/time.h" +#include "net/base/data_url.h" +#include "net/base/load_flags.h" +#include "net/base/mime_util.h" +#include "net/base/net_errors.h" +#include "net/base/net_util.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_util.h" +#include "net/url_request/url_request.h" +#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" +#include "third_party/WebKit/public/platform/WebHTTPLoadInfo.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/platform/WebURLError.h" +#include "third_party/WebKit/public/platform/WebURLLoadTiming.h" +#include "third_party/WebKit/public/platform/WebURLLoaderClient.h" +#include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "third_party/WebKit/public/platform/WebURLResponse.h" +#include "third_party/WebKit/public/web/WebSecurityPolicy.h" +#include "webkit/child/ftp_directory_listing_response_delegate.h" +#include "webkit/child/multipart_response_delegate.h" +#include "webkit/child/resource_loader_bridge.h" +#include "webkit/child/webkitplatformsupport_impl.h" +#include "webkit/child/weburlrequest_extradata_impl.h" +#include "webkit/child/weburlresponse_extradata_impl.h" +#include "webkit/common/resource_request_body.h" + +using base::Time; +using base::TimeTicks; +using blink::WebData; +using blink::WebHTTPBody; +using blink::WebHTTPHeaderVisitor; +using blink::WebHTTPLoadInfo; +using blink::WebReferrerPolicy; +using blink::WebSecurityPolicy; +using blink::WebString; +using blink::WebURL; +using blink::WebURLError; +using blink::WebURLLoadTiming; +using blink::WebURLLoader; +using blink::WebURLLoaderClient; +using blink::WebURLRequest; +using blink::WebURLResponse; + +namespace webkit_glue { + +// Utilities ------------------------------------------------------------------ + +namespace { + +const char kThrottledErrorDescription[] = + "Request throttled. Visit http://dev.chromium.org/throttling for more " + "information."; + +class HeaderFlattener : public WebHTTPHeaderVisitor { + public: + explicit HeaderFlattener(int load_flags) + : load_flags_(load_flags), + has_accept_header_(false) { + } + + virtual void visitHeader(const WebString& name, const WebString& value) { + // Headers are latin1. + const std::string& name_latin1 = name.latin1(); + const std::string& value_latin1 = value.latin1(); + + // Skip over referrer headers found in the header map because we already + // pulled it out as a separate parameter. + if (LowerCaseEqualsASCII(name_latin1, "referer")) + return; + + // Skip over "Cache-Control: max-age=0" header if the corresponding + // load flag is already specified. FrameLoader sets both the flag and + // the extra header -- the extra header is redundant since our network + // implementation will add the necessary headers based on load flags. + // See http://code.google.com/p/chromium/issues/detail?id=3434. + if ((load_flags_ & net::LOAD_VALIDATE_CACHE) && + LowerCaseEqualsASCII(name_latin1, "cache-control") && + LowerCaseEqualsASCII(value_latin1, "max-age=0")) + return; + + if (LowerCaseEqualsASCII(name_latin1, "accept")) + has_accept_header_ = true; + + if (!buffer_.empty()) + buffer_.append("\r\n"); + buffer_.append(name_latin1 + ": " + value_latin1); + } + + const std::string& GetBuffer() { + // In some cases, WebKit doesn't add an Accept header, but not having the + // header confuses some web servers. See bug 808613. + if (!has_accept_header_) { + if (!buffer_.empty()) + buffer_.append("\r\n"); + buffer_.append("Accept: */*"); + has_accept_header_ = true; + } + return buffer_; + } + + private: + int load_flags_; + std::string buffer_; + bool has_accept_header_; +}; + +// Extracts the information from a data: url. +bool GetInfoFromDataURL(const GURL& url, + ResourceResponseInfo* info, + std::string* data, + int* error_code) { + std::string mime_type; + std::string charset; + if (net::DataURL::Parse(url, &mime_type, &charset, data)) { + *error_code = net::OK; + // Assure same time for all time fields of data: URLs. + Time now = Time::Now(); + info->load_timing.request_start = TimeTicks::Now(); + info->load_timing.request_start_time = now; + info->request_time = now; + info->response_time = now; + info->headers = NULL; + info->mime_type.swap(mime_type); + info->charset.swap(charset); + info->security_info.clear(); + info->content_length = data->length(); + info->encoded_data_length = 0; + + return true; + } + + *error_code = net::ERR_INVALID_URL; + return false; +} + +typedef ResourceDevToolsInfo::HeadersVector HeadersVector; + +// Converts timing data from |load_timing| to the format used by WebKit. +void PopulateURLLoadTiming(const net::LoadTimingInfo& load_timing, + WebURLLoadTiming* url_timing) { + DCHECK(!load_timing.request_start.is_null()); + + const TimeTicks kNullTicks; + url_timing->initialize(); + url_timing->setRequestTime( + (load_timing.request_start - kNullTicks).InSecondsF()); + url_timing->setProxyStart( + (load_timing.proxy_resolve_start - kNullTicks).InSecondsF()); + url_timing->setProxyEnd( + (load_timing.proxy_resolve_end - kNullTicks).InSecondsF()); + url_timing->setDNSStart( + (load_timing.connect_timing.dns_start - kNullTicks).InSecondsF()); + url_timing->setDNSEnd( + (load_timing.connect_timing.dns_end - kNullTicks).InSecondsF()); + url_timing->setConnectStart( + (load_timing.connect_timing.connect_start - kNullTicks).InSecondsF()); + url_timing->setConnectEnd( + (load_timing.connect_timing.connect_end - kNullTicks).InSecondsF()); + url_timing->setSSLStart( + (load_timing.connect_timing.ssl_start - kNullTicks).InSecondsF()); + url_timing->setSSLEnd( + (load_timing.connect_timing.ssl_end - kNullTicks).InSecondsF()); + url_timing->setSendStart( + (load_timing.send_start - kNullTicks).InSecondsF()); + url_timing->setSendEnd( + (load_timing.send_end - kNullTicks).InSecondsF()); + url_timing->setReceiveHeadersEnd( + (load_timing.receive_headers_end - kNullTicks).InSecondsF()); +} + +net::RequestPriority ConvertWebKitPriorityToNetPriority( + const WebURLRequest::Priority& priority) { + switch (priority) { + case WebURLRequest::PriorityVeryHigh: + return net::HIGHEST; + + case WebURLRequest::PriorityHigh: + return net::MEDIUM; + + case WebURLRequest::PriorityMedium: + return net::LOW; + + case WebURLRequest::PriorityLow: + return net::LOWEST; + + case WebURLRequest::PriorityVeryLow: + return net::IDLE; + + case WebURLRequest::PriorityUnresolved: + default: + NOTREACHED(); + return net::LOW; + } +} + +} // namespace + +// WebURLLoaderImpl::Context -------------------------------------------------- + +// This inner class exists since the WebURLLoader may be deleted while inside a +// call to WebURLLoaderClient. The bridge requires its Peer to stay alive +// until it receives OnCompletedRequest. +class WebURLLoaderImpl::Context : public base::RefCounted<Context>, + public ResourceLoaderBridge::Peer { + public: + explicit Context(WebURLLoaderImpl* loader); + + WebURLLoaderClient* client() const { return client_; } + void set_client(WebURLLoaderClient* client) { client_ = client; } + + void Cancel(); + void SetDefersLoading(bool value); + void DidChangePriority(WebURLRequest::Priority new_priority); + void Start( + const WebURLRequest& request, + ResourceLoaderBridge::SyncLoadResponse* sync_load_response, + WebKitPlatformSupportImpl* platform); + + // ResourceLoaderBridge::Peer methods: + virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE; + virtual bool OnReceivedRedirect( + const GURL& new_url, + const ResourceResponseInfo& info, + bool* has_new_first_party_for_cookies, + GURL* new_first_party_for_cookies) OVERRIDE; + virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE; + virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE; + virtual void OnReceivedData(const char* data, + int data_length, + int encoded_data_length) OVERRIDE; + virtual void OnReceivedCachedMetadata(const char* data, int len) OVERRIDE; + virtual void OnCompletedRequest( + int error_code, + bool was_ignored_by_handler, + bool stale_copy_in_cache, + const std::string& security_info, + const base::TimeTicks& completion_time, + int64 total_transfer_size) OVERRIDE; + + private: + friend class base::RefCounted<Context>; + virtual ~Context() {} + + // We can optimize the handling of data URLs in most cases. + bool CanHandleDataURL(const GURL& url) const; + void HandleDataURL(); + + WebURLLoaderImpl* loader_; + WebURLRequest request_; + WebURLLoaderClient* client_; + WebReferrerPolicy referrer_policy_; + scoped_ptr<ResourceLoaderBridge> bridge_; + scoped_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_; + scoped_ptr<MultipartResponseDelegate> multipart_delegate_; + scoped_ptr<ResourceLoaderBridge> completed_bridge_; +}; + +WebURLLoaderImpl::Context::Context(WebURLLoaderImpl* loader) + : loader_(loader), + client_(NULL), + referrer_policy_(blink::WebReferrerPolicyDefault) { +} + +void WebURLLoaderImpl::Context::Cancel() { + // The bridge will still send OnCompletedRequest, which will Release() us, so + // we don't do that here. + if (bridge_) + bridge_->Cancel(); + + // Ensure that we do not notify the multipart delegate anymore as it has + // its own pointer to the client. + if (multipart_delegate_) + multipart_delegate_->Cancel(); + + // Do not make any further calls to the client. + client_ = NULL; + loader_ = NULL; +} + +void WebURLLoaderImpl::Context::SetDefersLoading(bool value) { + if (bridge_) + bridge_->SetDefersLoading(value); +} + +void WebURLLoaderImpl::Context::DidChangePriority( + WebURLRequest::Priority new_priority) { + if (bridge_) + bridge_->DidChangePriority( + ConvertWebKitPriorityToNetPriority(new_priority)); +} + +void WebURLLoaderImpl::Context::Start( + const WebURLRequest& request, + ResourceLoaderBridge::SyncLoadResponse* sync_load_response, + WebKitPlatformSupportImpl* platform) { + DCHECK(!bridge_.get()); + + request_ = request; // Save the request. + + GURL url = request.url(); + if (url.SchemeIs("data") && CanHandleDataURL(url)) { + if (sync_load_response) { + // This is a sync load. Do the work now. + sync_load_response->url = url; + std::string data; + GetInfoFromDataURL(sync_load_response->url, sync_load_response, + &sync_load_response->data, + &sync_load_response->error_code); + } else { + AddRef(); // Balanced in OnCompletedRequest + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(&Context::HandleDataURL, this)); + } + return; + } + + GURL referrer_url( + request.httpHeaderField(WebString::fromUTF8("Referer")).latin1()); + const std::string& method = request.httpMethod().latin1(); + + int load_flags = net::LOAD_NORMAL; + switch (request.cachePolicy()) { + case WebURLRequest::ReloadIgnoringCacheData: + // Required by LayoutTests/http/tests/misc/refresh-headers.php + load_flags |= net::LOAD_VALIDATE_CACHE; + break; + case WebURLRequest::ReturnCacheDataElseLoad: + load_flags |= net::LOAD_PREFERRING_CACHE; + break; + case WebURLRequest::ReturnCacheDataDontLoad: + load_flags |= net::LOAD_ONLY_FROM_CACHE; + break; + case WebURLRequest::UseProtocolCachePolicy: + break; + } + + if (request.reportUploadProgress()) + load_flags |= net::LOAD_ENABLE_UPLOAD_PROGRESS; + if (request.reportLoadTiming()) + load_flags |= net::LOAD_ENABLE_LOAD_TIMING; + if (request.reportRawHeaders()) + load_flags |= net::LOAD_REPORT_RAW_HEADERS; + + if (!request.allowCookies() || !request.allowStoredCredentials()) { + load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES; + load_flags |= net::LOAD_DO_NOT_SEND_COOKIES; + } + + if (!request.allowStoredCredentials()) + load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA; + + if (request.targetType() == WebURLRequest::TargetIsXHR && + (url.has_username() || url.has_password())) { + load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN; + } + + HeaderFlattener flattener(load_flags); + request.visitHTTPHeaderFields(&flattener); + + // TODO(brettw) this should take parameter encoding into account when + // creating the GURLs. + + ResourceLoaderBridge::RequestInfo request_info; + request_info.method = method; + request_info.url = url; + request_info.first_party_for_cookies = request.firstPartyForCookies(); + request_info.referrer = referrer_url; + request_info.headers = flattener.GetBuffer(); + request_info.load_flags = load_flags; + // requestor_pid only needs to be non-zero if the request originates outside + // the render process, so we can use requestorProcessID even for requests + // from in-process plugins. + request_info.requestor_pid = request.requestorProcessID(); + request_info.request_type = + ResourceType::FromTargetType(request.targetType()); + request_info.priority = + ConvertWebKitPriorityToNetPriority(request.priority()); + request_info.appcache_host_id = request.appCacheHostID(); + request_info.routing_id = request.requestorID(); + request_info.download_to_file = request.downloadToFile(); + request_info.has_user_gesture = request.hasUserGesture(); + request_info.extra_data = request.extraData(); + referrer_policy_ = request.referrerPolicy(); + request_info.referrer_policy = request.referrerPolicy(); + bridge_.reset(platform->CreateResourceLoader(request_info)); + + if (!request.httpBody().isNull()) { + // GET and HEAD requests shouldn't have http bodies. + DCHECK(method != "GET" && method != "HEAD"); + const WebHTTPBody& httpBody = request.httpBody(); + size_t i = 0; + WebHTTPBody::Element element; + scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody; + while (httpBody.elementAt(i++, element)) { + switch (element.type) { + case WebHTTPBody::Element::TypeData: + if (!element.data.isEmpty()) { + // WebKit sometimes gives up empty data to append. These aren't + // necessary so we just optimize those out here. + request_body->AppendBytes( + element.data.data(), static_cast<int>(element.data.size())); + } + break; + case WebHTTPBody::Element::TypeFile: + if (element.fileLength == -1) { + request_body->AppendFileRange( + base::FilePath::FromUTF16Unsafe(element.filePath), + 0, kuint64max, base::Time()); + } else { + request_body->AppendFileRange( + base::FilePath::FromUTF16Unsafe(element.filePath), + static_cast<uint64>(element.fileStart), + static_cast<uint64>(element.fileLength), + base::Time::FromDoubleT(element.modificationTime)); + } + break; + case WebHTTPBody::Element::TypeFileSystemURL: { + GURL file_system_url = element.fileSystemURL; + DCHECK(file_system_url.SchemeIsFileSystem()); + request_body->AppendFileSystemFileRange( + file_system_url, + static_cast<uint64>(element.fileStart), + static_cast<uint64>(element.fileLength), + base::Time::FromDoubleT(element.modificationTime)); + break; + } + case WebHTTPBody::Element::TypeBlob: + request_body->AppendBlob(element.blobUUID.utf8()); + break; + default: + NOTREACHED(); + } + } + request_body->set_identifier(request.httpBody().identifier()); + bridge_->SetRequestBody(request_body.get()); + } + + if (sync_load_response) { + bridge_->SyncLoad(sync_load_response); + return; + } + + if (bridge_->Start(this)) { + AddRef(); // Balanced in OnCompletedRequest + } else { + bridge_.reset(); + } +} + +void WebURLLoaderImpl::Context::OnUploadProgress(uint64 position, uint64 size) { + if (client_) + client_->didSendData(loader_, position, size); +} + +bool WebURLLoaderImpl::Context::OnReceivedRedirect( + const GURL& new_url, + const ResourceResponseInfo& info, + bool* has_new_first_party_for_cookies, + GURL* new_first_party_for_cookies) { + if (!client_) + return false; + + WebURLResponse response; + response.initialize(); + PopulateURLResponse(request_.url(), info, &response); + + // TODO(darin): We lack sufficient information to construct the actual + // request that resulted from the redirect. + WebURLRequest new_request(new_url); + new_request.setFirstPartyForCookies(request_.firstPartyForCookies()); + new_request.setDownloadToFile(request_.downloadToFile()); + + WebString referrer_string = WebString::fromUTF8("Referer"); + WebString referrer = WebSecurityPolicy::generateReferrerHeader( + referrer_policy_, + new_url, + request_.httpHeaderField(referrer_string)); + if (!referrer.isEmpty()) + new_request.setHTTPReferrer(referrer, referrer_policy_); + + std::string method = request_.httpMethod().utf8(); + std::string new_method = net::URLRequest::ComputeMethodForRedirect( + method, response.httpStatusCode()); + new_request.setHTTPMethod(WebString::fromUTF8(new_method)); + if (new_method == method) + new_request.setHTTPBody(request_.httpBody()); + + client_->willSendRequest(loader_, new_request, response); + request_ = new_request; + *has_new_first_party_for_cookies = true; + *new_first_party_for_cookies = request_.firstPartyForCookies(); + + // Only follow the redirect if WebKit left the URL unmodified. + if (new_url == GURL(new_request.url())) + return true; + + // We assume that WebKit only changes the URL to suppress a redirect, and we + // assume that it does so by setting it to be invalid. + DCHECK(!new_request.url().isValid()); + return false; +} + +void WebURLLoaderImpl::Context::OnReceivedResponse( + const ResourceResponseInfo& info) { + if (!client_) + return; + + WebURLResponse response; + response.initialize(); + PopulateURLResponse(request_.url(), info, &response); + + bool show_raw_listing = (GURL(request_.url()).query() == "raw"); + + if (info.mime_type == "text/vnd.chromium.ftp-dir") { + if (show_raw_listing) { + // Set the MIME type to plain text to prevent any active content. + response.setMIMEType("text/plain"); + } else { + // We're going to produce a parsed listing in HTML. + response.setMIMEType("text/html"); + } + } + + scoped_refptr<Context> protect(this); + client_->didReceiveResponse(loader_, response); + + // We may have been cancelled after didReceiveResponse, which would leave us + // without a client and therefore without much need to do further handling. + if (!client_) + return; + + DCHECK(!ftp_listing_delegate_.get()); + DCHECK(!multipart_delegate_.get()); + if (info.headers.get() && info.mime_type == "multipart/x-mixed-replace") { + std::string content_type; + info.headers->EnumerateHeader(NULL, "content-type", &content_type); + + std::string mime_type; + std::string charset; + bool had_charset = false; + std::string boundary; + net::HttpUtil::ParseContentType(content_type, &mime_type, &charset, + &had_charset, &boundary); + base::TrimString(boundary, " \"", &boundary); + + // If there's no boundary, just handle the request normally. In the gecko + // code, nsMultiMixedConv::OnStartRequest throws an exception. + if (!boundary.empty()) { + multipart_delegate_.reset( + new MultipartResponseDelegate(client_, loader_, response, boundary)); + } + } else if (info.mime_type == "text/vnd.chromium.ftp-dir" && + !show_raw_listing) { + ftp_listing_delegate_.reset( + new FtpDirectoryListingResponseDelegate(client_, loader_, response)); + } +} + +void WebURLLoaderImpl::Context::OnDownloadedData(int len, + int encoded_data_length) { + if (client_) + client_->didDownloadData(loader_, len, encoded_data_length); +} + +void WebURLLoaderImpl::Context::OnReceivedData(const char* data, + int data_length, + int encoded_data_length) { + if (!client_) + return; + + if (ftp_listing_delegate_) { + // The FTP listing delegate will make the appropriate calls to + // client_->didReceiveData and client_->didReceiveResponse. + ftp_listing_delegate_->OnReceivedData(data, data_length); + } else if (multipart_delegate_) { + // The multipart delegate will make the appropriate calls to + // client_->didReceiveData and client_->didReceiveResponse. + multipart_delegate_->OnReceivedData(data, data_length, encoded_data_length); + } else { + client_->didReceiveData(loader_, data, data_length, encoded_data_length); + } +} + +void WebURLLoaderImpl::Context::OnReceivedCachedMetadata( + const char* data, int len) { + if (client_) + client_->didReceiveCachedMetadata(loader_, data, len); +} + +void WebURLLoaderImpl::Context::OnCompletedRequest( + int error_code, + bool was_ignored_by_handler, + bool stale_copy_in_cache, + const std::string& security_info, + const base::TimeTicks& completion_time, + int64 total_transfer_size) { + if (ftp_listing_delegate_) { + ftp_listing_delegate_->OnCompletedRequest(); + ftp_listing_delegate_.reset(NULL); + } else if (multipart_delegate_) { + multipart_delegate_->OnCompletedRequest(); + multipart_delegate_.reset(NULL); + } + + // Prevent any further IPC to the browser now that we're complete, but + // don't delete it to keep any downloaded temp files alive. + DCHECK(!completed_bridge_.get()); + completed_bridge_.swap(bridge_); + + if (client_) { + if (error_code != net::OK) { + client_->didFail(loader_, CreateError(request_.url(), + stale_copy_in_cache, + error_code)); + } else { + client_->didFinishLoading( + loader_, (completion_time - TimeTicks()).InSecondsF(), + total_transfer_size); + } + } + + // We are done with the bridge now, and so we need to release the reference + // to ourselves that we took on behalf of the bridge. This may cause our + // destruction. + Release(); +} + +bool WebURLLoaderImpl::Context::CanHandleDataURL(const GURL& url) const { + DCHECK(url.SchemeIs("data")); + + // Optimize for the case where we can handle a data URL locally. We must + // skip this for data URLs targetted at frames since those could trigger a + // download. + // + // NOTE: We special case MIME types we can render both for performance + // reasons as well as to support unit tests, which do not have an underlying + // ResourceLoaderBridge implementation. + +#if defined(OS_ANDROID) + // For compatibility reasons on Android we need to expose top-level data:// + // to the browser. + if (request_.targetType() == WebURLRequest::TargetIsMainFrame) + return false; +#endif + + if (request_.targetType() != WebURLRequest::TargetIsMainFrame && + request_.targetType() != WebURLRequest::TargetIsSubframe) + return true; + + std::string mime_type, unused_charset; + if (net::DataURL::Parse(url, &mime_type, &unused_charset, NULL) && + net::IsSupportedMimeType(mime_type)) + return true; + + return false; +} + +void WebURLLoaderImpl::Context::HandleDataURL() { + ResourceResponseInfo info; + int error_code; + std::string data; + + if (GetInfoFromDataURL(request_.url(), &info, &data, &error_code)) { + OnReceivedResponse(info); + if (!data.empty()) + OnReceivedData(data.data(), data.size(), 0); + } + + OnCompletedRequest(error_code, false, false, info.security_info, + base::TimeTicks::Now(), 0); +} + +// WebURLLoaderImpl ----------------------------------------------------------- + +WebURLLoaderImpl::WebURLLoaderImpl(WebKitPlatformSupportImpl* platform) + : context_(new Context(this)), + platform_(platform) { +} + +WebURLLoaderImpl::~WebURLLoaderImpl() { + cancel(); +} + +WebURLError WebURLLoaderImpl::CreateError(const WebURL& unreachable_url, + bool stale_copy_in_cache, + int reason) { + WebURLError error; + error.domain = WebString::fromUTF8(net::kErrorDomain); + error.reason = reason; + error.unreachableURL = unreachable_url; + error.staleCopyInCache = stale_copy_in_cache; + if (reason == net::ERR_ABORTED) { + error.isCancellation = true; + } else if (reason == net::ERR_TEMPORARILY_THROTTLED) { + error.localizedDescription = WebString::fromUTF8( + kThrottledErrorDescription); + } else { + error.localizedDescription = WebString::fromUTF8( + net::ErrorToString(reason)); + } + return error; +} + +void WebURLLoaderImpl::PopulateURLResponse(const GURL& url, + const ResourceResponseInfo& info, + WebURLResponse* response) { + response->setURL(url); + response->setResponseTime(info.response_time.ToDoubleT()); + response->setMIMEType(WebString::fromUTF8(info.mime_type)); + response->setTextEncodingName(WebString::fromUTF8(info.charset)); + response->setExpectedContentLength(info.content_length); + response->setSecurityInfo(info.security_info); + response->setAppCacheID(info.appcache_id); + response->setAppCacheManifestURL(info.appcache_manifest_url); + response->setWasCached(!info.load_timing.request_start_time.is_null() && + info.response_time < info.load_timing.request_start_time); + response->setRemoteIPAddress( + WebString::fromUTF8(info.socket_address.host())); + response->setRemotePort(info.socket_address.port()); + response->setConnectionID(info.load_timing.socket_log_id); + response->setConnectionReused(info.load_timing.socket_reused); + response->setDownloadFilePath(info.download_file_path.AsUTF16Unsafe()); + WebURLResponseExtraDataImpl* extra_data = + new WebURLResponseExtraDataImpl(info.npn_negotiated_protocol); + response->setExtraData(extra_data); + extra_data->set_was_fetched_via_spdy(info.was_fetched_via_spdy); + extra_data->set_was_npn_negotiated(info.was_npn_negotiated); + extra_data->set_was_alternate_protocol_available( + info.was_alternate_protocol_available); + extra_data->set_connection_info(info.connection_info); + extra_data->set_was_fetched_via_proxy(info.was_fetched_via_proxy); + + // If there's no received headers end time, don't set load timing. This is + // the case for non-HTTP requests, requests that don't go over the wire, and + // certain error cases. + if (!info.load_timing.receive_headers_end.is_null()) { + WebURLLoadTiming timing; + PopulateURLLoadTiming(info.load_timing, &timing); + response->setLoadTiming(timing); + } + + if (info.devtools_info.get()) { + WebHTTPLoadInfo load_info; + + load_info.setHTTPStatusCode(info.devtools_info->http_status_code); + load_info.setHTTPStatusText(WebString::fromLatin1( + info.devtools_info->http_status_text)); + load_info.setEncodedDataLength(info.encoded_data_length); + + load_info.setRequestHeadersText(WebString::fromLatin1( + info.devtools_info->request_headers_text)); + load_info.setResponseHeadersText(WebString::fromLatin1( + info.devtools_info->response_headers_text)); + const HeadersVector& request_headers = info.devtools_info->request_headers; + for (HeadersVector::const_iterator it = request_headers.begin(); + it != request_headers.end(); ++it) { + load_info.addRequestHeader(WebString::fromLatin1(it->first), + WebString::fromLatin1(it->second)); + } + const HeadersVector& response_headers = + info.devtools_info->response_headers; + for (HeadersVector::const_iterator it = response_headers.begin(); + it != response_headers.end(); ++it) { + load_info.addResponseHeader(WebString::fromLatin1(it->first), + WebString::fromLatin1(it->second)); + } + response->setHTTPLoadInfo(load_info); + } + + const net::HttpResponseHeaders* headers = info.headers.get(); + if (!headers) + return; + + WebURLResponse::HTTPVersion version = WebURLResponse::Unknown; + if (headers->GetHttpVersion() == net::HttpVersion(0, 9)) + version = WebURLResponse::HTTP_0_9; + else if (headers->GetHttpVersion() == net::HttpVersion(1, 0)) + version = WebURLResponse::HTTP_1_0; + else if (headers->GetHttpVersion() == net::HttpVersion(1, 1)) + version = WebURLResponse::HTTP_1_1; + response->setHTTPVersion(version); + response->setHTTPStatusCode(headers->response_code()); + response->setHTTPStatusText(WebString::fromLatin1(headers->GetStatusText())); + + // TODO(darin): We should leverage HttpResponseHeaders for this, and this + // should be using the same code as ResourceDispatcherHost. + // TODO(jungshik): Figure out the actual value of the referrer charset and + // pass it to GetSuggestedFilename. + std::string value; + headers->EnumerateHeader(NULL, "content-disposition", &value); + response->setSuggestedFileName( + net::GetSuggestedFilename(url, + value, + std::string(), // referrer_charset + std::string(), // suggested_name + std::string(), // mime_type + std::string())); // default_name + + Time time_val; + if (headers->GetLastModifiedValue(&time_val)) + response->setLastModifiedDate(time_val.ToDoubleT()); + + // Build up the header map. + void* iter = NULL; + std::string name; + while (headers->EnumerateHeaderLines(&iter, &name, &value)) { + response->addHTTPHeaderField(WebString::fromLatin1(name), + WebString::fromLatin1(value)); + } +} + +void WebURLLoaderImpl::loadSynchronously(const WebURLRequest& request, + WebURLResponse& response, + WebURLError& error, + WebData& data) { + ResourceLoaderBridge::SyncLoadResponse sync_load_response; + context_->Start(request, &sync_load_response, platform_); + + const GURL& final_url = sync_load_response.url; + + // TODO(tc): For file loads, we may want to include a more descriptive + // status code or status text. + int error_code = sync_load_response.error_code; + if (error_code != net::OK) { + response.setURL(final_url); + error.domain = WebString::fromUTF8(net::kErrorDomain); + error.reason = error_code; + error.unreachableURL = final_url; + return; + } + + PopulateURLResponse(final_url, sync_load_response, &response); + + data.assign(sync_load_response.data.data(), + sync_load_response.data.size()); +} + +void WebURLLoaderImpl::loadAsynchronously(const WebURLRequest& request, + WebURLLoaderClient* client) { + DCHECK(!context_->client()); + + context_->set_client(client); + context_->Start(request, NULL, platform_); +} + +void WebURLLoaderImpl::cancel() { + context_->Cancel(); +} + +void WebURLLoaderImpl::setDefersLoading(bool value) { + context_->SetDefersLoading(value); +} + +void WebURLLoaderImpl::didChangePriority(WebURLRequest::Priority new_priority) { + context_->DidChangePriority(new_priority); +} + +} // namespace webkit_glue diff --git a/webkit/child/weburlloader_impl.h b/webkit/child/weburlloader_impl.h new file mode 100644 index 0000000..3c69923 --- /dev/null +++ b/webkit/child/weburlloader_impl.h @@ -0,0 +1,51 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_CHILD_WEBURLLOADER_IMPL_H_ +#define WEBKIT_CHILD_WEBURLLOADER_IMPL_H_ + +#include "base/memory/ref_counted.h" +#include "third_party/WebKit/public/platform/WebURLLoader.h" +#include "webkit/child/webkit_child_export.h" + +namespace webkit_glue { + +class WebKitPlatformSupportImpl; +struct ResourceResponseInfo; + +class WebURLLoaderImpl : public blink::WebURLLoader { + public: + explicit WebURLLoaderImpl(WebKitPlatformSupportImpl* platform); + virtual ~WebURLLoaderImpl(); + + static blink::WebURLError CreateError(const blink::WebURL& unreachable_url, + bool stale_copy_in_cache, + int reason); + WEBKIT_CHILD_EXPORT static void PopulateURLResponse( + const GURL& url, + const ResourceResponseInfo& info, + blink::WebURLResponse* response); + + // WebURLLoader methods: + virtual void loadSynchronously( + const blink::WebURLRequest& request, + blink::WebURLResponse& response, + blink::WebURLError& error, + blink::WebData& data); + virtual void loadAsynchronously( + const blink::WebURLRequest& request, + blink::WebURLLoaderClient* client); + virtual void cancel(); + virtual void setDefersLoading(bool value); + virtual void didChangePriority(blink::WebURLRequest::Priority new_priority); + + private: + class Context; + scoped_refptr<Context> context_; + WebKitPlatformSupportImpl* platform_; +}; + +} // namespace webkit_glue + +#endif // WEBKIT_CHILD_WEBURLLOADER_IMPL_H_ |