WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
144628
[Curl] WebSocket platform part is not implemented.
https://bugs.webkit.org/show_bug.cgi?id=144628
Summary
[Curl] WebSocket platform part is not implemented.
peavo
Reported
2015-05-05 08:37:57 PDT
The Curl platform code for WebSockets has not been implemented yet.
Attachments
Patch
(12.00 KB, patch)
2015-05-05 08:41 PDT
,
peavo
no flags
Details
Formatted Diff
Diff
Patch
(11.82 KB, patch)
2015-05-07 13:26 PDT
,
peavo
no flags
Details
Formatted Diff
Diff
Patch
(11.66 KB, patch)
2015-05-08 10:26 PDT
,
peavo
no flags
Details
Formatted Diff
Diff
Patch
(12.21 KB, patch)
2015-05-11 11:50 PDT
,
peavo
no flags
Details
Formatted Diff
Diff
Patch
(12.46 KB, patch)
2015-05-13 03:53 PDT
,
peavo
darin
: review+
Details
Formatted Diff
Diff
Show Obsolete
(4)
View All
Add attachment
proposed patch, testcase, etc.
peavo
Comment 1
2015-05-05 08:41:39 PDT
Created
attachment 252386
[details]
Patch
peavo
Comment 2
2015-05-05 08:43:20 PDT
The patch passes all http websocket tests :)
Darin Adler
Comment 3
2015-05-05 09:04:39 PDT
Comment on
attachment 252386
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=252386&action=review
Code looks OK, but lots of room for improvement.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:57 > +class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase {
Are we guaranteed that all the ref/deref are on the same thread? I am concerned that is not so.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:59 > + static PassRefPtr<SocketStreamHandle> create(const URL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); }
Should return Ref, not PassRefPtr.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:63 > +protected:
A class that is never used as a base class should not have any protected members at all. These should all be private, not protected.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:69 > + bool readData(CURL* curlHandle); > + bool sendData(CURL* curlHandle); > + bool waitForAvailableData(CURL* curlHandle, int selectTimeoutMS);
These CURL* don’t need argument names in the header, and also, should be CURL&. The selectTimeoutMS is an old fashioned choice and not what we should do in new code. A better type for the argument would be std::chrono::microseconds or perhaps std::chrono::milliseconds. Either way we would avoid all the comments about units and actually get compile time checking for it.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:72 > + static void worker(void*);
This should be a lambda inside the member function that needs it, not a static member function.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:90 > + class SocketData {
This seems like a peculiar class. Maybe it should just be a struct instead of a class.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:106 > + const char* m_data;
This needs to be a std::unique_ptr<const char[]>; doing all the new and delete by hand is not a good idea.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:57 > setClient(0);
nullptr
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:100 > + char* data = new char[bufferSize];
Should use unique_ptr, not manual new/delete.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:108 > + callOnMainThread(didReceiveData, this);
It would be better to use a lambda here rather than the mess with a static data member and a case of the data pointer inside it. If we had a thread safe reference count then we could use have the lambda capture a reference count to the handle, and then we would not need to use cancelCallOnMainThread in the destructor.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:222 > + SocketStreamHandle* handle = reinterpret_cast<SocketStreamHandle*>(context);
This should be static_cast, not reinterpret_cast.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:233 > + auto receiveData = m_receiveData; > + m_receiveData.clear();
This should use WTF::move rather than copy and clear. Much more efficient and required if we change SocketData to read-only, which we should do.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:237 > + for (auto socketData : receiveData) {
This needs to be auto& to avoid copying the socket data.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:252 > + SocketStreamHandle* handle = reinterpret_cast<SocketStreamHandle*>(context);
This should be static_cast instead.
peavo
Comment 4
2015-05-05 10:13:35 PDT
Thanks for reviewing :) Will upload another patch soon.
peavo
Comment 5
2015-05-07 13:26:51 PDT
Created
attachment 252612
[details]
Patch
peavo
Comment 6
2015-05-07 13:31:26 PDT
(In reply to
comment #3
)
> > > Source/WebCore/platform/network/curl/SocketStreamHandle.h:69 > > + bool readData(CURL* curlHandle); > > + bool sendData(CURL* curlHandle); > > + bool waitForAvailableData(CURL* curlHandle, int selectTimeoutMS); > > These CURL* don’t need argument names in the header, and also, should be > CURL&. >
I didn't change the parameter type, as CURL& didn't compile, since CURL is of type void.
Darin Adler
Comment 7
2015-05-07 15:29:59 PDT
Comment on
attachment 252612
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=252612&action=review
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:49 > +#include <wtf/threading.h>
This should have a capital "t". The headers here aren’t sorted alphabetically the way the WebKit style guide says they should be.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:87 > + class SocketData {
This should just be a struct, not a class. I don’t see us getting any benefit from making it a class.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:89 > + SocketData(const char* data, int size)
I think it’s too subtle that this takes ownership of the data. Making this a struct might help.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:100 > + SocketData(SocketData&& other) > + { > + m_data = WTF::move(other.m_data); > + m_size = other.m_size; > + other.m_size = 0; > + }
Is it important that the other’s size gets set to 0 when moving? If not, then I suggest we just let the compiler generate this.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:104 > + ~SocketData() > + { > + }
No need to define this.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:69 > + char* copy = new char[length];
This should go right into a std::unique_ptr when it’s allocated.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:101 > + m_receiveData.append(SocketData(data.release(), bytesRead));
This shows us we have a poor design for SocketData. It’s not good to call unique_ptr.release just to put something into another unique_ptr. If SocketData was a struct we could just write: m_receiveData.append(SocketData { WTF::move(data), bytesRead });
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:127 > + auto sendData = WTF::move(m_sendData.at(0)); > + m_sendData.remove(0);
Should use takeFirst, not move/at/remove. And the fact that a Vector doesn’t have a takeFirst should make you realize that this should be a Duque, not a Vector.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:143 > + char* copy = new char[restLength];
Should go right into a std::unique_ptr.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:173 > + if (!m_workerThread) {
Early return would be better than nesting the entire function inside an if.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:174 > + ref();
Need a comment explaining where the deref that matches this is.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:184 > + CString host = m_url.host().ascii();
The String::ascii() function should not be used unless there is a guarantee that all characters are ASCII. I don’t think there is a guarantee that all characters from URL::host will be ASCII. Maybe you want latin1() or utf8()?
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:217 > + if (m_workerThread) {
Early return would be better than nesting the entire function inside an if.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:218 > + m_stopThread = true;
Probably needs to be an atomic bool, not just a normal bool.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:220 > + m_workerThread = 0;
nullptr
peavo
Comment 8
2015-05-08 10:26:11 PDT
Created
attachment 252729
[details]
Patch
peavo
Comment 9
2015-05-08 10:27:41 PDT
(In reply to
comment #7
) Thanks again for helpful review :)
> > > Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:220 > > + m_workerThread = 0; > > nullptr
I didn't change this, as m_workerThread does not seem to be of pointer type.
Darin Adler
Comment 10
2015-05-10 14:31:32 PDT
Comment on
attachment 252729
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=252729&action=review
lets not use this unnecessary std::unique_ptr
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:48 > +#if PLATFORM(WIN) > +#include <windows.h> > +#include <winsock2.h> > +#endif > + > +#include <curl/curl.h> > + > +#include <mutex> > + > +#include <wtf/Deque.h> > #include <wtf/RefCounted.h> > +#include <wtf/Threading.h>
These aren’t sorted in the normal WebKit project way.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:88 > + const char* data() const { return m_data.get(); } > + int size() const { return m_size; }
No need for these.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:90 > + std::unique_ptr<const char[]> m_data;
Should just name this data.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:91 > + int m_size;
Should just name this size. I also suggest initializing it to zero instead of leaving it uninitialized.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:99 > + Deque<std::unique_ptr<SocketData>> m_sendData; > + Deque<std::unique_ptr<SocketData>> m_receiveData;
These should be Deque<SocketData> instead of Deque<std::unique_ptr<SocketData>). There’s no need for all the extra heap allocation.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:51 > + startThread();
Should probably ASSERT(isMainThread()) here. But also, why do we need to start the thread? I don’t think we do.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:57 > + stopThread();
Should just be ASSERT(!m_workerThread). The handle is ref'd as long as the thread is going.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:58 > + setClient(nullptr);
I don’t understand the value of doing this. The setClient function has no side effects, and once the handle is deleted the null pointer can be overwritten by other random values. I don’t think this class needs a destructor at all, although perhaps the logging and assertions would be OK.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:70 > + std::unique_ptr<const char[]> copy(new const char[length]); > + memcpy(const_cast<char*>(copy.get()), data, length);
Should be able to allocate a std::unique_ptr<char[]> and then pass it to a function expecting a std::unique_ptr<const char[]> and have it be converted. We’d avoid a const_cast that way.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:124 > + std::lock_guard<std::mutex> lock(m_mutexSend);
Do we really need to lock during the actual send? This seems like a really long time to hold a lock.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:144 > + std::unique_ptr<const char[]> copy(new const char[restLength]); > + memcpy(const_cast<char*>(copy.get()), sendData->data() + totalBytesSent, restLength); > + m_sendData.prepend(std::unique_ptr<SocketData>(new SocketData { WTF::move(copy), restLength } ));
Would be nice to share this code with platformSend.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:158 > + timeout.tv_sec = 0; > + timeout.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(selectTimeout).count();
This can do something crazy thing if selectTimeout is 1 second or more or if it’s negative.
http://stackoverflow.com/questions/17402657/how-to-convert-stdchronosystem-clockduration-into-struct-timeval
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:188 > + CString host = m_url.host().utf8(); > + curl_easy_setopt(curlHandle, CURLOPT_URL, host.data());
No need for the local variable here.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:200 > + if (refCount() > 1) > + didOpenSocket();
This check of refCount is peculiar. Is this an important optimization?
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:217 > +void SocketStreamHandle::stopThread()
This function needs an ASSERT(isMainThread())
peavo
Comment 11
2015-05-11 11:50:48 PDT
Created
attachment 252878
[details]
Patch
peavo
Comment 12
2015-05-11 12:03:19 PDT
(In reply to
comment #10
)
> Comment on
attachment 252729
[details]
> Patch >
Thank you for your patience :)
> View in context: >
https://bugs.webkit.org/attachment.cgi?id=252729&action=review
> > lets not use this unnecessary std::unique_ptr > > > Source/WebCore/platform/network/curl/SocketStreamHandle.h:48 > > +#if PLATFORM(WIN) > > +#include <windows.h> > > +#include <winsock2.h> > > +#endif > > + > > +#include <curl/curl.h> > > + > > +#include <mutex> > > + > > +#include <wtf/Deque.h> > > #include <wtf/RefCounted.h> > > +#include <wtf/Threading.h> > > These aren’t sorted in the normal WebKit project way. >
winsock2.h is needed before curl.h is included, so I kept this.
> > > Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:51 > > + startThread(); > > Should probably ASSERT(isMainThread()) here. > > But also, why do we need to start the thread? I don’t think we do. >
startThread() seems to be needed here, many tests timed out without it.
> > > Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:70 > > + std::unique_ptr<const char[]> copy(new const char[length]); > > + memcpy(const_cast<char*>(copy.get()), data, length); > > Should be able to allocate a std::unique_ptr<char[]> and then pass it to a > function expecting a std::unique_ptr<const char[]> and have it be converted. > We’d avoid a const_cast that way.
> MSVC didn't want to convert this, I got the error: error C2664: 'std::unique_ptr<const char [],std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : cannot convert argument 1 from 'std::unique_ptr<char [],std::default_delete<_Ty>>' to 'std::unique_ptr<const char [],std::default_delete<_Ty>> &&'
> > > Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:200 > > + if (refCount() > 1) > > + didOpenSocket(); > > This check of refCount is peculiar. Is this an important optimization? >
I'm also not too happy with this :) I added it to fix a crash where the call was invoked on the main thread after all other references were released, and the SocketStreamClient was deleted. Accessing the SocketStreamClient in didOpenSocket() then caused a crash. I had to add a SocketData constructor since m_sendData.append(SocketData { WTF::move(copy), length }) didn't compile with MSVC. The error I got was: error C2440 : '<function-style-cast>' : cannot convert from 'initializer-list' to 'WebCore::SocketStreamHandle::SocketData' 1> No constructor could take the source type, or constructor overload resolution was ambiguous I also had to add a move constructor, otherwise I got an error stating that Deque.h (line 422) was trying to reference the deleted unique_ptr copy constructor.
Alex Christensen
Comment 13
2015-05-11 16:09:18 PDT
> MSVC didn't want to convert this, I got the error: > > error C2664: 'std::unique_ptr<const char > [],std::default_delete<_Ty>>::unique_ptr(const > std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : > cannot convert argument 1 from 'std::unique_ptr<char > [],std::default_delete<_Ty>>' to 'std::unique_ptr<const char > [],std::default_delete<_Ty>> &&'
If this really is a bug in MSVC, could you use const_cast to add const instead of taking it away? That would be nicer.
> I had to add a SocketData constructor since m_sendData.append(SocketData { > WTF::move(copy), length }) didn't compile with MSVC. The error I got was: > > error C2440 : '<function-style-cast>' : cannot convert from > 'initializer-list' to 'WebCore::SocketStreamHandle::SocketData' > 1> No constructor could take the source type, or constructor > overload resolution was ambiguous
Does it work to call the constructor without any initializer-list? (no {})
Darin Adler
Comment 14
2015-05-11 17:28:48 PDT
Comment on
attachment 252878
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=252878&action=review
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:77 > + std::unique_ptr<const char[]> createCopy(const char* data, int length);
Should be static.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:99 > + SocketData(std::unique_ptr<const char[]>&& source, int length) > + { > + data = WTF::move(source); > + size = length; > + } > + > + SocketData(SocketData&& other) > + { > + data = WTF::move(other.data); > + size = other.size; > + other.size = 0; > + }
I don’t understand why you had to define these.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:71 > + m_sendData.append(SocketData(WTF::move(copy), length));
Should just be SocketData { WTF::move(copy), length } and then it should work without a constructor.
> Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:215 > + if (refCount() > 1) > + didOpenSocket();
Needs a comment explaining why it’s here. Something like how you replied to my query about this.
peavo
Comment 15
2015-05-13 03:53:59 PDT
Created
attachment 253030
[details]
Patch
peavo
Comment 16
2015-05-13 04:01:34 PDT
(In reply to
comment #14
)
> Comment on
attachment 252878
[details]
> Patch
> Thanks again :)
> > > Source/WebCore/platform/network/curl/SocketStreamHandle.h:99 > > + SocketData(std::unique_ptr<const char[]>&& source, int length) > > + { > > + data = WTF::move(source); > > + size = length; > > + } > > + > > + SocketData(SocketData&& other) > > + { > > + data = WTF::move(other.data); > > + size = other.size; > > + other.size = 0; > > + } > > I don’t understand why you had to define these. > > > Source/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp:71 > > + m_sendData.append(SocketData(WTF::move(copy), length)); > > Should just be SocketData { WTF::move(copy), length } and then it should > work without a constructor. >
I'm sorry, but I don't seem to be able to get rid of these constructors. When I remove them, I get the following error: 1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(611): error C2280: 'std::unique_ptr<char [],std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function 1> with 1> [ 1> _Ty=char [] 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\memory(1618) : see declaration of 'std::unique_ptr<char [],std::default_delete<_Ty>>::unique_ptr' 1> with 1> [ 1> _Ty=char [] 1> ] 1> This diagnostic occurred in the compiler generated function 'WebCore::SocketStreamHandle::SocketData::SocketData(const WebCore::SocketStreamHandle::SocketData &)' ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== I believe this happens because Deque::append and Deque::prepend makes MSVC generate a SocketData copy constructor, which is not possible since the copy constructor in unique_ptr is deleted. There seems to be reports of similar problems:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ace575e6-3969-4672-9db1-85c9d6588e4a/cant-put-class-with-uniqueptr-member-in-stl-container?forum=vclanguage
http://stackoverflow.com/questions/10133591/using-smart-pointers-in-a-struct-or-class
Is this a MSVC problem? I assume gcc doesn't have these problems.
peavo
Comment 17
2015-05-13 04:03:28 PDT
(In reply to
comment #13
)
> > MSVC didn't want to convert this, I got the error: > > > > error C2664: 'std::unique_ptr<const char > > [],std::default_delete<_Ty>>::unique_ptr(const > > std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : > > cannot convert argument 1 from 'std::unique_ptr<char > > [],std::default_delete<_Ty>>' to 'std::unique_ptr<const char > > [],std::default_delete<_Ty>> &&' > If this really is a bug in MSVC, could you use const_cast to add const > instead of taking it away? That would be nicer. > > I had to add a SocketData constructor since m_sendData.append(SocketData { > > WTF::move(copy), length }) didn't compile with MSVC. The error I got was: > > > > error C2440 : '<function-style-cast>' : cannot convert from > > 'initializer-list' to 'WebCore::SocketStreamHandle::SocketData' > > 1> No constructor could take the source type, or constructor > > overload resolution was ambiguous > Does it work to call the constructor without any initializer-list? (no {})
Thanks for looking into this :) I removed the const modifier from the unique_ptr member in the last patch to avoid all the casting. I hope this is acceptable :)
Darin Adler
Comment 18
2015-05-13 12:09:05 PDT
(In reply to
comment #16
)
> I believe this happens because Deque::append and Deque::prepend makes MSVC > generate a SocketData copy constructor, which is not possible since the copy > constructor in unique_ptr is deleted.
As you say, I think this is indeed an MSVC bug.
Darin Adler
Comment 19
2015-05-13 12:09:18 PDT
Comment on
attachment 253030
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=253030&action=review
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:92 > + SocketData(std::unique_ptr<char[]>&& source, int length) > + { > + data = WTF::move(source); > + size = length; > + }
Really irritating that we have to do this to work around a bug in MSVC, but I’m pretty sure that is indeed what we are doing, working around a bug. Two separate related bugs, I guess.
> Source/WebCore/platform/network/curl/SocketStreamHandle.h:99 > + SocketData(SocketData&& other) > + { > + data = WTF::move(other.data); > + size = other.size; > + other.size = 0; > + }
Really irritating that we have to do this to work around a bug in MSVC, but I’m pretty sure that is indeed what we are doing, working around a bug. Two separate related bugs, I guess.
peavo
Comment 20
2015-05-13 12:20:23 PDT
(In reply to
comment #19
)
> Comment on
attachment 253030
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=253030&action=review
> > > Source/WebCore/platform/network/curl/SocketStreamHandle.h:92 > > + SocketData(std::unique_ptr<char[]>&& source, int length) > > + { > > + data = WTF::move(source); > > + size = length; > > + } > > Really irritating that we have to do this to work around a bug in MSVC, but > I’m pretty sure that is indeed what we are doing, working around a bug. Two > separate related bugs, I guess. >
Thanks for reviewing :) I can try to remember to revisit this code when we move to the next MSVC version.
peavo
Comment 21
2015-05-15 06:53:47 PDT
Committed
r184389
: <
http://trac.webkit.org/changeset/184389
>
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug