OpenSSL服务器没有从WKWebView接收媒体(音频/视频)请求 [英] OpenSSL server not receiving requests for media (audio/video) from WKWebView

查看:176
本文介绍了OpenSSL服务器没有从WKWebView接收媒体(音频/视频)请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们要完成的目标是将本地视频资产(存储在磁盘上)加载到WKWebView实例中,以用作WebGL中的纹理。到目前为止,我们一直使用绑定到localhost(GCDWebServer)的服务器完成此操作,并将本地源代码作为HTML字符串加载(在此示例中)baseURL: http:// localhost:8989 / ,然后使用以下代码行播放视频:

The goal we’re trying to accomplish is to load a local video asset (stored on disk) into a WKWebView instance, to be used as a texture in WebGL. Up until now, we have been accomplishing this using a server bound to localhost (GCDWebServer), and loading the local source code as an HTML string with (in this example,) baseURL:"http://localhost:8989/", and then playing the video with the following line of code:

<video src="test.mp4" width="320" height="240" preload="auto" playsinline autoplay muted></video>

然而,随着Apple ATS政策即将发生变化,我们现在需要通过HTTPS实现这一目标。我们的新服务器实现基于OpenSSL,包含在下面:

However, with imminent changes to Apple’s ATS policy, we now need this to happen over HTTPS. Our new server implementation is based on OpenSSL and is included below:

#import "SSLServer.h"
#import "Logging.h"
#import "Util.h"

#import "SSLServerResponse.h"

#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"

#define FAIL -1
#define SSL_SERVER_UPDATE_INTERVAL 0.0f

@interface SSLServer ()
{
    BOOL _keepAlive;
    NSUInteger _port;

    NSString* _directoryPath;
    NSString* _certFilepath;

    SSLServerStartCompletionHandler _startCompletionHandler;
}
@end

@implementation SSLServer

-(instancetype)initWithPort:(NSUInteger)port directoryPath:(NSString*)directoryPath andCertFilepath:(NSString*)certFilepath {

    self = [super init];

    if (self) {
        _keepAlive = YES;
        _port = 8989; //port;
        _certFilepath = certFilepath ? certFilepath : @"";
        _directoryPath = directoryPath;
    }

    return self;
}

-(void)startWithCompletionHandler:(SSLServerStartCompletionHandler)handler {
    _startCompletionHandler = handler;

    SSL_CTX *ctx;
    int server;

    SSL_library_init();

    //Initialize SSL
    ctx = [self initServerCTX];
    if (ctx == NULL) {
        LogInfoPrivate(@"[SSLServer] : Failed to create SSL context for some reason");
        return;
    }

    //Load certs
    [self loadCertificates:ctx certFile:_certFilepath keyFile:_certFilepath];

    //Create server socket
    server = [self openListener:_port];
    if (server == -1) {
        _startCompletionHandler(NO, (NSUInteger)_port);
    } else {
       _startCompletionHandler(YES, (NSUInteger)_port);
    }
    _startCompletionHandler = nil;

    while (_keepAlive) {
        struct sockaddr_in addr;
        socklen_t len = sizeof(addr);
        SSL *ssl;

        LogInfoPrivate(@"[SSLServer] : Listening on port: %lu", (unsigned long)_port);

        //Accept connection as usual
        int client = accept(server, (struct sockaddr*)&addr, &len);
        LogInfoPrivate(@"[SSLServer] : Connection: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        LogInfoPrivate(@"[SSLServer] : Port:%lu\n", (unsigned long)_port);

        //Get new SSL state with context
        ssl = SSL_new(ctx);

        //Set connection socket to SSL state
        SSL_set_fd(ssl, client);

        //Service connection             

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            [self servlet:ssl directoryPath:_directoryPath];
        });

        [NSThread sleepForTimeInterval:SSL_SERVER_UPDATE_INTERVAL];
    }

    //Close server socket
    close(server);

    //Release context
    SSL_CTX_free(ctx);
}

-(int)openListener:(NSUInteger)port {
    int sock;
    struct sockaddr_in addr;

    sock = socket(PF_INET, SOCK_STREAM, 0);
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons((unsigned long)port);
    addr.sin_addr.s_addr = INADDR_ANY;

    socklen_t len = sizeof(addr);

    if (bind(sock, (struct sockaddr*)&addr, len) != 0) {
        LogErrorPrivate(@"[SSLServer] : Can't bind port");
        return -1;
    }

    if (listen(sock, 10) != 0) {
        LogErrorPrivate(@"[SSLServer] : Can't configure listening port");
        return -1;
    }

    // when sin_port is init'd as '0', socket lib will randomize the port, so, we grab the bound port here.
    if (port == 0) {
        if (getsockname(sock, (struct sockaddr *)&addr, &len) == -1) {
            LogErrorPrivate(@"[SSLServer] : Could not retrieve random port number");
            return -1;
        } else {
            _port = ntohs(addr.sin_port);
        }
    }

    return sock;
}

-(SSL_CTX*)initServerCTX {
    const SSL_METHOD *method;
    SSL_CTX *ctx;

    //Load & register all cryptos, etc.
    OpenSSL_add_all_algorithms();

    //Load all error 4messages
    SSL_load_error_strings();

    //Create new server-method instance
    method = TLSv1_2_server_method();

    //Create new context from method
    ctx = SSL_CTX_new(method);
    if (ctx == NULL) {
        ERR_print_errors_fp(stderr);
        return NULL;
    }

    return ctx;
}

-(void)loadCertificates:(SSL_CTX*)ctx certFile:(NSString*)certFile keyFile:(NSString*)keyFile {
    //Set the local certificate from CertFile
    if (SSL_CTX_use_certificate_file(ctx, [certFile UTF8String], SSL_FILETYPE_PEM) <= 0 ) {
        ERR_print_errors_fp(stderr);
        return;
    }

    //Set the private key from KeyFile (may be the same as CertFile)
    if (SSL_CTX_use_PrivateKey_file(ctx, [keyFile UTF8String], SSL_FILETYPE_PEM) <= 0 ) {
        ERR_print_errors_fp(stderr);
        return;
    }

    //Verify private key
    if (!SSL_CTX_check_private_key(ctx) ) {
        LogErrorPrivate(@"[SSLServer] : Private key does not match the public certificate");
        return;
    }
}

-(void)showCerts:(SSL*)ssl {
    X509 *cert;
    char *line;

    //Get certificates (if available)
    cert = SSL_get_peer_certificate(ssl);
    if (cert != NULL) {
        LogInfoPrivate(@"[SSLServer] : Server certificates:");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        LogInfoPrivate(@"[SSLServer] : Subject: %s", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        LogInfoPrivate(@"[SSLServer] : Issuer: %s", line);
        free(line);
        X509_free(cert);
    } else {
        LogInfoPrivate(@"[SSLServer] : No certificates.");
    }
}

//Serve the connection
-(void)servlet:(SSL*)ssl directoryPath:(NSString*)directoryPath {
    char buf[1024];
    int sd, bytes;

    //Do SSL-protocol accept
    if (SSL_accept(ssl) == FAIL) {
        ERR_print_errors_fp(stderr);
    } else {
        //Get any certificates
        [self showCerts:ssl];

        //Get request
        bytes = SSL_read(ssl, buf, sizeof(buf));
        if (bytes > 0) {
            buf[bytes] = 0;
            LogInfoPrivate(@"[SSLServer] Client msg: \"%s\"", buf);

            NSArray* requestElements = [[NSString stringWithUTF8String:buf] componentsSeparatedByString:@" "];
            NSString* resource = [requestElements[1] lastPathComponent];
            NSString* resourcePath = [directoryPath stringByAppendingPathComponent:resource];
            LogInfoPrivate(@"[SSLServer] Resource path: %@", resource);

            //Configure the response
            SSLServerResponse* response = [[SSLServerResponse alloc] initWithResourcePath:resourcePath chunked:YES];
            [response configure];

            //Write the response
            for (NSData* data in response.payload) {
                SSL_write(ssl, (const char*)[data bytes], (int)[data length]);
            }
        } else {
            LogInfoPrivate(@"[SSLServer] : Nothing to send back");
            ERR_print_errors_fp(stderr);
        }
    }

    //Get socket connection
    sd = SSL_get_fd(ssl);

    //Release SSL state
    SSL_free(ssl);

    //Close connection
    close(sd);
}

-(void)finish {
    _keepAlive = NO;
}
@end

我们遇到的问题是图像( .png)和文字正确送达;但是,音频和视频不是。我们一直在监控Charles的网络流量,甚至没有任何请求来自Web视图。更具体地说,除了对图像和javascript的GET请求之外,套接字上不会发生通信。对于图像和文本,我们看到Charles和Web视图中的请求正在获取身份验证质询回调。我们通过将'allowsInlineMediaPlayback'设置为'YES'并将'mediaPlaybackRequiresUserAction'设置为'NO'来配置我们的WKWebViewConfiguration。有人可以解释为什么只有一些请求被从网络视图中解雇?

The problem we’re encountering is that images (.png) and text are served correctly; however, audio and video are not. We’ve been monitoring the network traffic in Charles and no requests are even coming out of the web view. More specifically, apart from GET requests for images and javascript, no communication occurs on the socket. For images and text, we see the requests in Charles and the web view is getting the authentication challenge callback. We have configured our WKWebViewConfiguration by setting ‘allowsInlineMediaPlayback’ to ‘YES’ and ‘mediaPlaybackRequiresUserAction’ to ‘NO’. Can someone please explain why only some requests are being fired from the web view?

推荐答案

我们在 http:// +:13333 ,但是当我们使用此内容在WKWebView中加载我们的htmlString时,就会发生这种情况 http: // localhost:13333

We had a httpListener on "http://+:13333", but nothings happen when we load our htmlString in WKWebView with this content "http://localhost:13333".

我们的解决方案是将localhost替换为127.0.0.1。

Our solution was to replace the "localhost" with "127.0.0.1".

也许这是WKWebView的一般问题?!

Maybe it is a genaral problem by WKWebView?!

这篇关于OpenSSL服务器没有从WKWebView接收媒体(音频/视频)请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆