// // Example // man // // Created by man 11/11/2018. // Copyright © 2020 man. All rights reserved. // @import Foundation; @protocol _CustomHTTPProtocolDelegate; /*! An NSURLProtocol subclass that overrides the built-in HTTP/HTTPS protocol to intercept * authentication challenges for subsystems, ilke UIWebView, that don't otherwise allow it. * To use this class you should set up your delegate (+setDelegate:) and then call +start. * If you don't call +start the class is completely benign. * * The really tricky stuff here is related to the authentication challenge delegate * callbacks; see the docs for _CustomHTTPProtocolDelegate for the details. */ @interface _CustomHTTPProtocol : NSURLProtocol /*! Call this to start the module. Prior to this the module is just dormant, and * all HTTP requests proceed as normal. After this all HTTP and HTTPS requests * go through this module. */ + (void)start; //liman + (void)stop; /*! Sets the delegate for the class. * \details Note that there's one delegate for the entire class, not one per * instance of the class as is more normal. The delegate is not retained in general, * but is retained for the duration of any given call. Once you set the delegate to nil * you can be assured that it won't be called unretained (that is, by the time that * -setDelegate: returns, we've already done all possible retains on the delegate). * \param newValue The new delegate to use; may be nil. */ + (void)setDelegate:(id<_CustomHTTPProtocolDelegate>)newValue; /*! Returns the class delegate. */ + (id<_CustomHTTPProtocolDelegate>)delegate; @property (atomic, strong, readonly ) NSURLAuthenticationChallenge * pendingChallenge; ///< The current authentication challenge; it's only safe to access this from the main thread. /*! Call this method to resolve an authentication challeng. This must be called on the main thread. * \param challenge The challenge to resolve. This must match the pendingChallenge property. * \param credential The credential to use, or nil to continue without a credential. */ - (void)resolveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge withCredential:(NSURLCredential *)credential; @end /*! The delegate for the CustomHTTPProtocol class (not its instances). * \details The delegate handles two different types of callbacks: * * - authentication challenges * * - logging * * The latter is very simple. The former is quite tricky. The basic idea is that each CustomHTTPProtocol * instance sends the delegate a serialised stream of authentication challenges, each of which it is * expected to resolve. The sequence is as follows: * * -# It calls -customHTTPProtocol:canAuthenticateAgainstProtectionSpace: to determine if the delegate * can handle the challenge. This can be call on an arbitrary background thread. * * -# If the delegate returns YES, it calls -customHTTPProtocol:didReceiveAuthenticationChallenge: to * actually process the challenge. This is always called on the main thread. The delegate can resolve * the challenge synchronously (that is, before returning from the call) or it can return from the call * and then, later on, resolve the challenge. Resolving the challenge involves calling * -[CustomHTTPProtocol resolveAuthenticationChallenge:withCredential:], which also must be called * on the main thread. Between the calls to -customHTTPProtocol:didReceiveAuthenticationChallenge: * and -[CustomHTTPProtocol resolveAuthenticationChallenge:withCredential:], the protocol's * pendingChallenge property will contain the challenge. * * -# While there is a pending challenge, the protocol may call -customHTTPProtocol:didCancelAuthenticationChallenge: * to cancel the challenge. This is always called on the main thread. * * Note that this design follows the original NSURLConnection model, not the newer NSURLConnection model * (introduced in OS X 10.7 / iOS 5) or the NSURLSession model, because of my concerns about performance. * Specifically, -customHTTPProtocol:canAuthenticateAgainstProtectionSpace: can be called on any thread * but -customHTTPProtocol:didReceiveAuthenticationChallenge: is called on the main thread. If I unified * them I'd end up calling the resulting single routine on the main thread, which meanings a lot more * bouncing between threads, much of which would be pointless in the common case where you don't want to * customise the default behaviour. Alternatively I could call the unified routine on an arbitrary thread, * but that would make it harder for clients and require a major rework of my implementation. */ @protocol _CustomHTTPProtocolDelegate @optional /*! Called by an CustomHTTPProtocol instance to ask the delegate whether it's prepared to handle * a particular authentication challenge. Can be called on any thread. * \param protocol The protocol instance itself; will not be nil. * \param protectionSpace The protection space for the authentication challenge; will not be nil. * \returns Return YES if you want the -customHTTPProtocol:didReceiveAuthenticationChallenge: delegate * callback, or NO for the challenge to be handled in the default way. */ - (BOOL)customHTTPProtocol:(_CustomHTTPProtocol *)protocol canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace; /*! Called by an CustomHTTPProtocol instance to request that the delegate process on authentication * challenge. Will be called on the main thread. Unless the challenge is cancelled (see below) * the delegate must eventually resolve it by calling -resolveAuthenticationChallenge:withCredential:. * \param protocol The protocol instance itself; will not be nil. * \param challenge The authentication challenge; will not be nil. */ - (void)customHTTPProtocol:(_CustomHTTPProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; /*! Called by an CustomHTTPProtocol instance to cancel an issued authentication challenge. * Will be called on the main thread. * \param protocol The protocol instance itself; will not be nil. * \param challenge The authentication challenge; will not be nil; will match the challenge * previously issued by -customHTTPProtocol:canAuthenticateAgainstProtectionSpace:. */ - (void)customHTTPProtocol:(_CustomHTTPProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; /*! Called by the CustomHTTPProtocol to log various bits of information. * Can be called on any thread. * \param protocol The protocol instance itself; nil to indicate log messages from the class itself. * \param format A standard NSString-style format string; will not be nil. * \param arguments Arguments for that format string. */ - (void)customHTTPProtocol:(_CustomHTTPProtocol *)protocol logWithFormat:(NSString *)format arguments:(va_list)arguments; @end