Overview
Comment: | OFHTTPServer: Support for using multiple threads |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
607cd05ad7a68d5ce0994a18c73f9526 |
User & Date: | js on 2019-03-03 12:40:15 |
Other Links: | manifest | tags |
Context
2019-03-08
| ||
00:35 | Use dot syntax check-in: bceb7ed4c9 user: js tags: trunk | |
2019-03-03
| ||
12:40 | OFHTTPServer: Support for using multiple threads check-in: 607cd05ad7 user: js tags: trunk | |
2019-02-24
| ||
16:28 | OFMutableURL: Add -[standardizePath] check-in: 555e18ace0 user: js tags: trunk | |
Changes
Modified src/OFHTTPServer.h from [00ea092795] to [3b876afaf6].
︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #ifndef OF_HAVE_SOCKETS # error No sockets available! #endif OF_ASSUME_NONNULL_BEGIN @class OFHTTPRequest; @class OFHTTPResponse; @class OFHTTPServer; @class OFStream; @class OFTCPSocket; /*! | > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #ifndef OF_HAVE_SOCKETS # error No sockets available! #endif OF_ASSUME_NONNULL_BEGIN @class OFArray; @class OFHTTPRequest; @class OFHTTPResponse; @class OFHTTPServer; @class OFStream; @class OFTCPSocket; /*! |
︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | uint16_t _port; bool _usesTLS; OFString *_Nullable _certificateFile, *_Nullable _privateKeyFile; const char *_Nullable _privateKeyPassphrase; id <OFHTTPServerDelegate> _Nullable _delegate; OFString *_Nullable _name; OF_KINDOF(OFTCPSocket *) _Nullable _listeningSocket; } /*! * @brief The host on which the HTTP server will listen. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *host; /*! * @brief The port on which the HTTP server will listen. */ @property (nonatomic) uint16_t port; /*! * @brief Whether the HTTP server uses TLS. */ @property (nonatomic) bool usesTLS; /*! * @brief The path to the X.509 certificate file to use for TLS. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile; /*! * @brief The path to the PKCS#8 private key file to use for TLS. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile; /*! * @brief The passphrase to decrypt the PKCS#8 private key file for TLS. * * @warning You have to ensure that this is in secure memory protected from * swapping! This is also the reason why this is not an OFString. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) const char *privateKeyPassphrase; /*! * @brief The delegate for the HTTP server. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id <OFHTTPServerDelegate> delegate; /*! * @brief The server name the server presents to clients. * * Setting it to `nil` means no `Server` header will be sent, unless one is * specified in the response headers. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | uint16_t _port; bool _usesTLS; OFString *_Nullable _certificateFile, *_Nullable _privateKeyFile; const char *_Nullable _privateKeyPassphrase; id <OFHTTPServerDelegate> _Nullable _delegate; OFString *_Nullable _name; OF_KINDOF(OFTCPSocket *) _Nullable _listeningSocket; #ifdef OF_HAVE_THREADS size_t _numberOfThreads, _nextThreadIndex; OFArray *_threadPool; #endif } /*! * @brief The host on which the HTTP server will listen. * * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *host; /*! * @brief The port on which the HTTP server will listen. * * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property (nonatomic) uint16_t port; /*! * @brief Whether the HTTP server uses TLS. * * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property (nonatomic) bool usesTLS; /*! * @brief The path to the X.509 certificate file to use for TLS. * * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile; /*! * @brief The path to the PKCS#8 private key file to use for TLS. * * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile; /*! * @brief The passphrase to decrypt the PKCS#8 private key file for TLS. * * @warning You have to ensure that this is in secure memory protected from * swapping! This is also the reason why this is not an OFString. * * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) const char *privateKeyPassphrase; /*! * @brief The delegate for the HTTP server. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id <OFHTTPServerDelegate> delegate; #ifdef OF_HAVE_THREADS /*! * @brief The number of threads the OFHTTPServer should use. * * If this is larger than 1 (the default), one thread will be used to accept * incoming connections and all others will be used to handle connections. * * For maximum CPU utilization, set this to `[OFSystemInfo numberOfCPUs] + 1`. * * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property (nonatomic) size_t numberOfThreads; #endif /*! * @brief The server name the server presents to clients. * * Setting it to `nil` means no `Server` header will be sent, unless one is * specified in the response headers. */ |
︙ | ︙ |
Modified src/OFHTTPServer.m from [e825f297c5] to [503afee9ba].
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include "config.h" #include <stdlib.h> #include <string.h> #import "OFHTTPServer.h" #import "OFData.h" #import "OFDate.h" #import "OFDictionary.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFNumber.h" #import "OFTCPSocket.h" #import "OFTLSSocket.h" #import "OFTimer.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" | > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include "config.h" #include <stdlib.h> #include <string.h> #import "OFHTTPServer.h" #import "OFArray.h" #import "OFData.h" #import "OFDate.h" #import "OFDictionary.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFNumber.h" #import "OFTCPSocket.h" #import "OFTLSSocket.h" #import "OFThread.h" #import "OFTimer.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" |
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | uintmax_t _toRead; bool _atEndOfStream; } - (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock contentLength: (uintmax_t)contentLength; @end static const char * statusCodeToString(short code) { switch (code) { case 100: return "Continue"; | > > > > > > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | uintmax_t _toRead; bool _atEndOfStream; } - (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock contentLength: (uintmax_t)contentLength; @end #ifdef OF_HAVE_THREADS @interface OFHTTPServerThread: OFThread - (void)stop; @end #endif static const char * statusCodeToString(short code) { switch (code) { case 100: return "Continue"; |
︙ | ︙ | |||
713 714 715 716 717 718 719 720 | - (void)close { [_socket release]; _socket = nil; } @end | > | < | > > > > > > | > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | - (void)close { [_socket release]; _socket = nil; } @end #ifdef OF_HAVE_THREADS @implementation OFHTTPServerThread - (void)stop { [[OFRunLoop currentRunLoop] stop]; [self join]; } @end #endif @implementation OFHTTPServer @synthesize delegate = _delegate, name = _name; + (instancetype)server { return [[[self alloc] init] autorelease]; } - (instancetype)init { self = [super init]; _name = @"OFHTTPServer (ObjFW's HTTP server class " @"<https://heap.zone/objfw/>)"; #ifdef OF_HAVE_THREADS _numberOfThreads = 1; #endif return self; } - (void)dealloc { [self stop]; [_host release]; [_listeningSocket release]; [_name release]; [super dealloc]; } - (void)setHost: (OFString *)host { OFString *old; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; old = _host; _host = [host copy]; [old release]; } - (OFString *)host { return _host; } - (void)setPort: (uint16_t)port { if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; _port = port; } - (uint16_t)port { return _port; } - (void)setUsesTLS: (bool)usesTLS { if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; _usesTLS = usesTLS; } - (bool)usesTLS { return _usesTLS; } - (void)setCertificateFile: (OFString *)certificateFile { OFString *old; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; old = _certificateFile; _certificateFile = [certificateFile copy]; [old release]; } - (OFString *)certificateFile { return _certificateFile; } - (void)setPrivateKeyFile: (OFString *)privateKeyFile { OFString *old; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; old = _privateKeyFile; _privateKeyFile = [privateKeyFile copy]; [old release]; } - (OFString *)privateKeyFile { return _privateKeyFile; } - (void)setPrivateKeyPassphrase: (const char *)privateKeyPassphrase { if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; _privateKeyPassphrase = privateKeyPassphrase; } - (const char *)privateKeyPassphrase { return _privateKeyPassphrase; } #ifdef OF_HAVE_THREADS - (void)setNumberOfThreads: (size_t)numberOfThreadas { if (numberOfThreadas == 0) @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; _numberOfThreads = numberOfThreadas; } - (size_t)numberOfThreads { return _numberOfThreads; } #endif - (void)start { void *pool = objc_autoreleasePoolPush(); if (_host == nil) @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; if (_usesTLS) { |
︙ | ︙ | |||
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 | setPrivateKeyPassphrase: _privateKeyPassphrase]; } else _listeningSocket = [[OFTCPSocket alloc] init]; _port = [_listeningSocket bindToHost: _host port: _port]; [_listeningSocket listen]; [(OFTCPSocket *)_listeningSocket setDelegate: self]; [_listeningSocket asyncAccept]; } - (void)stop { [_listeningSocket cancelAsyncRequests]; [_listeningSocket release]; _listeningSocket = nil; } - (bool)socket: (OF_KINDOF(OFTCPSocket *))sock didAcceptSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket exception: (id)exception { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < > > | > | < > > > > | > > > | | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 | setPrivateKeyPassphrase: _privateKeyPassphrase]; } else _listeningSocket = [[OFTCPSocket alloc] init]; _port = [_listeningSocket bindToHost: _host port: _port]; [_listeningSocket listen]; #ifdef OF_HAVE_THREADS if (_numberOfThreads > 1) { OFMutableArray *threads = [OFMutableArray arrayWithCapacity: _numberOfThreads - 1]; for (size_t i = 1; i < _numberOfThreads; i++) { OFHTTPServerThread *thread = [OFHTTPServerThread thread]; [thread start]; [threads addObject: thread]; } [threads makeImmutable]; _threadPool = [threads copy]; } #endif [(OFTCPSocket *)_listeningSocket setDelegate: self]; [_listeningSocket asyncAccept]; objc_autoreleasePoolPop(pool); } - (void)stop { [_listeningSocket cancelAsyncRequests]; [_listeningSocket release]; _listeningSocket = nil; #ifdef OF_HAVE_THREADS for (OFHTTPServerThread *thread in _threadPool) [thread stop]; [_threadPool release]; _threadPool = nil; #endif } - (void)of_handleAcceptedSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket { OFHTTPServer_Connection *connection = [[[OFHTTPServer_Connection alloc] initWithSocket: acceptedSocket server: self] autorelease]; [(OFTCPSocket *)acceptedSocket setDelegate: connection]; [acceptedSocket asyncReadLine]; } - (bool)socket: (OF_KINDOF(OFTCPSocket *))sock didAcceptSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket exception: (id)exception { if (exception != nil) { if (![_delegate respondsToSelector: @selector(server:didReceiveExceptionOnListeningSocket:)]) return false; return [_delegate server: self didReceiveExceptionOnListeningSocket: exception]; } #ifdef OF_HAVE_THREADS if (_numberOfThreads > 1) { OFHTTPServerThread *thread = [_threadPool objectAtIndex: _nextThreadIndex]; if (++_nextThreadIndex >= _numberOfThreads - 1) _nextThreadIndex = 0; [self performSelector: @selector(of_handleAcceptedSocket:) onThread: thread withObject: acceptedSocket waitUntilDone: false]; } else #endif [self of_handleAcceptedSocket: acceptedSocket]; return true; } @end |