|
2 | 2 |
|
3 | 3 | import tech.gusavila92.apache.commons.codec.binary.Base64; |
4 | 4 | import tech.gusavila92.apache.commons.codec.digest.DigestUtils; |
5 | | -import tech.gusavila92.apache.http.Header; |
6 | | -import tech.gusavila92.apache.http.HttpException; |
7 | | -import tech.gusavila92.apache.http.HttpResponse; |
8 | | -import tech.gusavila92.apache.http.StatusLine; |
9 | | -import tech.gusavila92.apache.http.impl.io.DefaultHttpResponseParser; |
10 | | -import tech.gusavila92.apache.http.impl.io.HttpTransportMetricsImpl; |
11 | | -import tech.gusavila92.apache.http.impl.io.SessionInputBufferImpl; |
12 | | -import tech.gusavila92.apache.http.io.HttpMessageParser; |
13 | 5 | import tech.gusavila92.websocketclient.common.Utils; |
14 | 6 | import tech.gusavila92.websocketclient.exceptions.UnknownOpcodeException; |
15 | 7 | import tech.gusavila92.websocketclient.exceptions.IllegalSchemeException; |
@@ -697,12 +689,10 @@ private void startConnection() throws IOException { |
697 | 689 |
|
698 | 690 | InputStream inputStream = socket.getInputStream(); |
699 | 691 | verifyServerHandshake(inputStream, base64Key); |
700 | | - |
701 | | - writerThread.start(); |
702 | | - |
703 | 692 | notifyOnOpen(); |
| 693 | + writerThread.start(); |
704 | 694 |
|
705 | | - bis = new BufferedInputStream(socket.getInputStream(), 65536); |
| 695 | + bis = new BufferedInputStream(inputStream, 65536); |
706 | 696 | read(); |
707 | 697 | } |
708 | 698 |
|
@@ -773,71 +763,90 @@ private byte[] createHandshake(String base64Key) { |
773 | 763 | * @throws IOException |
774 | 764 | */ |
775 | 765 | private void verifyServerHandshake(InputStream inputStream, String secWebSocketKey) throws IOException { |
776 | | - try { |
777 | | - SessionInputBufferImpl sessionInputBuffer = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), |
778 | | - 8192); |
779 | | - sessionInputBuffer.bind(inputStream); |
780 | | - HttpMessageParser<HttpResponse> parser = new DefaultHttpResponseParser(sessionInputBuffer); |
781 | | - HttpResponse response = parser.parse(); |
782 | | - |
783 | | - StatusLine statusLine = response.getStatusLine(); |
784 | | - if (statusLine == null) { |
785 | | - throw new InvalidServerHandshakeException("There is no status line"); |
786 | | - } |
| 766 | + boolean finish = false; |
| 767 | + boolean lastLineBreak = false; |
| 768 | + LinkedList<String> lines = new LinkedList<String>(); |
| 769 | + |
| 770 | + do { |
| 771 | + boolean endOfLine = false; |
| 772 | + StringBuilder builder = new StringBuilder(); |
| 773 | + |
| 774 | + do { |
| 775 | + char c = (char) inputStream.read(); |
| 776 | + if (c == '\r') { |
| 777 | + c = (char) inputStream.read(); |
| 778 | + if (c == '\n') { |
| 779 | + endOfLine = true; |
| 780 | + if (lastLineBreak) { |
| 781 | + finish = true; |
| 782 | + } else { |
| 783 | + lastLineBreak = true; |
| 784 | + } |
| 785 | + } else { |
| 786 | + throw new InvalidServerHandshakeException("Invalid handshake format"); |
| 787 | + } |
| 788 | + } else { |
| 789 | + lastLineBreak = false; |
| 790 | + builder.append(c); |
| 791 | + } |
| 792 | + } while (!endOfLine); |
787 | 793 |
|
788 | | - int statusCode = statusLine.getStatusCode(); |
789 | | - if (statusCode != 101) { |
790 | | - throw new InvalidServerHandshakeException( |
791 | | - "Invalid status code. Expected 101, received: " + statusCode); |
792 | | - } |
| 794 | + lines.add(builder.toString()); |
| 795 | + } while (!finish); |
793 | 796 |
|
794 | | - Header[] upgradeHeader = response.getHeaders("Upgrade"); |
795 | | - if (upgradeHeader.length == 0) { |
796 | | - throw new InvalidServerHandshakeException("There is no header named Upgrade"); |
797 | | - } |
798 | | - String upgradeValue = upgradeHeader[0].getValue(); |
799 | | - if (upgradeValue == null) { |
800 | | - throw new InvalidServerHandshakeException("There is no value for header Upgrade"); |
801 | | - } |
802 | | - upgradeValue = upgradeValue.toLowerCase(); |
803 | | - if (!upgradeValue.equals("websocket")) { |
804 | | - throw new InvalidServerHandshakeException( |
805 | | - "Invalid value for header Upgrade. Expected: websocket, received: " + upgradeValue); |
806 | | - } |
| 797 | + String statusLine = lines.pollFirst(); |
| 798 | + if (statusLine == null) { |
| 799 | + throw new InvalidServerHandshakeException("There is no status line"); |
| 800 | + } |
807 | 801 |
|
808 | | - Header[] connectionHeader = response.getHeaders("Connection"); |
809 | | - if (connectionHeader.length == 0) { |
810 | | - throw new InvalidServerHandshakeException("There is no header named Connection"); |
811 | | - } |
812 | | - String connectionValue = connectionHeader[0].getValue(); |
813 | | - if (connectionValue == null) { |
814 | | - throw new InvalidServerHandshakeException("There is no value for header Connection"); |
815 | | - } |
816 | | - connectionValue = connectionValue.toLowerCase(); |
817 | | - if (!connectionValue.equals("upgrade")) { |
818 | | - throw new InvalidServerHandshakeException( |
819 | | - "Invalid value for header Connection. Expected: upgrade, received: " + connectionValue); |
| 802 | + String[] statusLineParts = statusLine.split(" "); |
| 803 | + if (statusLineParts.length > 1) { |
| 804 | + String statusCode = statusLineParts[1]; |
| 805 | + if (!statusCode.equals("101")) { |
| 806 | + throw new InvalidServerHandshakeException("Invalid status code. Expected 101, received: " + statusCode); |
820 | 807 | } |
| 808 | + } else { |
| 809 | + throw new InvalidServerHandshakeException("Invalid status line format"); |
| 810 | + } |
821 | 811 |
|
822 | | - Header[] secWebSocketAcceptHeader = response.getHeaders("Sec-WebSocket-Accept"); |
823 | | - if (secWebSocketAcceptHeader.length == 0) { |
824 | | - throw new InvalidServerHandshakeException("There is no header named Sec-WebSocket-Accept"); |
825 | | - } |
826 | | - String secWebSocketAcceptValue = secWebSocketAcceptHeader[0].getValue(); |
827 | | - if (secWebSocketAcceptValue == null) { |
828 | | - throw new InvalidServerHandshakeException("There is no value for header Sec-WebSocket-Accept"); |
| 812 | + lines.pollLast(); |
| 813 | + Map<String, String> headers = new HashMap<String, String>(); |
| 814 | + for (String s : lines) { |
| 815 | + String[] parts = s.split(":"); |
| 816 | + if (parts.length == 2) { |
| 817 | + headers.put(parts[0].trim(), parts[1].trim()); |
| 818 | + } else { |
| 819 | + throw new InvalidServerHandshakeException("Invalid headers format"); |
829 | 820 | } |
| 821 | + } |
830 | 822 |
|
831 | | - String keyConcatenation = secWebSocketKey + GUID; |
832 | | - byte[] sha1 = DigestUtils.sha1(keyConcatenation); |
833 | | - String secWebSocketAccept = Base64.encodeBase64String(sha1); |
834 | | - if (!secWebSocketAcceptValue.equals(secWebSocketAccept)) { |
835 | | - throw new InvalidServerHandshakeException( |
836 | | - "Invalid value for header Sec-WebSocket-Accept. Expected: " + secWebSocketAccept |
837 | | - + ", received: " + secWebSocketAcceptValue); |
838 | | - } |
839 | | - } catch (HttpException e) { |
840 | | - throw new InvalidServerHandshakeException(e.getMessage()); |
| 823 | + String upgradeValue = headers.get("Upgrade"); |
| 824 | + if (upgradeValue == null) { |
| 825 | + throw new InvalidServerHandshakeException("There is no header named Upgrade"); |
| 826 | + } |
| 827 | + upgradeValue = upgradeValue.toLowerCase(); |
| 828 | + if (!upgradeValue.equals("websocket")) { |
| 829 | + throw new InvalidServerHandshakeException("Invalid value for header Upgrade. Expected: websocket, received: " + upgradeValue); |
| 830 | + } |
| 831 | + |
| 832 | + String connectionValue = headers.get("Connection"); |
| 833 | + if (connectionValue == null) { |
| 834 | + throw new InvalidServerHandshakeException("There is no header named Connection"); |
| 835 | + } |
| 836 | + connectionValue = connectionValue.toLowerCase(); |
| 837 | + if (!connectionValue.equals("upgrade")) { |
| 838 | + throw new InvalidServerHandshakeException("Invalid value for header Connection. Expected: upgrade, received: " + connectionValue); |
| 839 | + } |
| 840 | + |
| 841 | + String secWebSocketAcceptValue = headers.get("Sec-WebSocket-Accept"); |
| 842 | + if (secWebSocketAcceptValue == null) { |
| 843 | + throw new InvalidServerHandshakeException("There is no header named Sec-WebSocket-Accept"); |
| 844 | + } |
| 845 | + String keyConcatenation = secWebSocketKey + GUID; |
| 846 | + byte[] sha1 = DigestUtils.sha1(keyConcatenation); |
| 847 | + String secWebSocketAccept = Base64.encodeBase64String(sha1); |
| 848 | + if (!secWebSocketAcceptValue.equals(secWebSocketAccept)) { |
| 849 | + throw new InvalidServerHandshakeException("Invalid value for header Sec-WebSocket-Accept. Expected: " + secWebSocketAccept + ", received: " + secWebSocketAcceptValue); |
841 | 850 | } |
842 | 851 | } |
843 | 852 |
|
|
0 commit comments