Пример #1
0
/*
 * Send back a simple error page
 */
void
http_response_send_error(struct http_response *resp,
	int code, const char *fmt, ...)
{
	struct http_request *const req = resp->msg->conn->req;
	const char *ua;
	FILE *fp;
	int i;

	/* Check headers already sent */
	if (resp->msg->hdrs_sent)
		return;

	/* Set response line info */
	http_response_set_header(resp, 0, HDR_REPLY_STATUS, "%d", code);
	http_response_set_header(resp, 0, HDR_REPLY_REASON,
	      "%s", http_response_status_msg(code));

	/* Set additional headers */
	http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE,
		"text/html; charset=iso-8859-1");

	/* Close connection for real errors */
	if (code >= 400) {
		http_response_set_header(resp,
		    0, _http_message_connection_header(resp->msg), "close");
	}

	/* Send error page body */
	if ((fp = http_response_get_output(resp, 1)) == NULL)
		return;
	fprintf(fp, "<HTML>\n<HEAD>\n<TITLE>%d %s</TITLE></HEAD>\n",
	    code, http_response_status_msg(code));
	fprintf(fp, "<BODY BGCOLOR=\"#FFFFFF\">\n<H3>%d %s</H3>\n",
	    code, http_response_status_msg(code));
	if (fmt != NULL) {
		va_list args;

		fprintf(fp, "<B>");
		va_start(args, fmt);
		vfprintf(fp, fmt, args);
		va_end(args);
		fprintf(fp, "</B>\n");
	}
#if 0
	fprintf(fp, "<P></P>\n<HR>\n");
	fprintf(fp, "<FONT SIZE=\"-1\"><EM>%s</EM></FONT>\n",
	    serv->server_name);
#endif

	/* Add fillter for IE */
	if ((ua = http_request_get_header(req, HTTP_HEADER_USER_AGENT)) != NULL
	    && strstr(ua, "IE") != NULL) {
		for (i = 0; i < 20; i++) {
			fprintf(fp, "<!-- FILLER TO MAKE INTERNET EXPLORER SHOW"
			    " THIS PAGE INSTEAD OF ITS OWN PAGE -->\n");
		}
	}
	fprintf(fp, "</BODY>\n</HTML>\n");
}
Пример #2
0
bool http_request_preform(http_request_t * req) {
	sstring_t ss;
	sstring_init(&ss, 100);
	char buffer[200] = {0};

	build_request_header(req, &ss);


	if (!http_conn_connect(req->conn)) {
		req->error = req->conn->error;
		return false;
	}
	// trigger STATE_OPENED.
	change_state(req, STATE_OPENED);

	//printf("request header: %s len:%d\n", pss->ptr, pss->len);
	int n = write(req->conn->connfd, ss.ptr, ss.len);

	//fetch header and stored in hash table.
	http_request_fetch_header(req);

	if(req->method != METHOD_HEAD) {
		change_state(req, STATE_LOADING);
		size_t complete = 0;
		size_t total = 0;
		char * content_length = http_request_get_header(req, "Content-Length");
		if(content_length) {
			total = atoi(content_length);
		}
		if(req->handlers.on_loadstart) {
			req->handlers.on_loadstart(req->handlers.loadstart_data);
		}
		if(req->handlers.on_progress) {
			req->handlers.on_progress(complete, total ,req->handlers.progress_data);
		}

		while((n = read(req->conn->connfd, buffer, 100))) {
			if(n < 0 ) {
				//error handle there
				break;
			}else {
				sstring_appendl(&req->response, buffer, n);
				complete += n;
				if(req->handlers.on_progress) {
					req->handlers.on_progress(complete, total, req->handlers.progress_data);
				}
			}
		}
		if(req->handlers.on_load) {
			req->handlers.on_load(buffer, req->handlers.load_data);
		}
	}

	change_state(req, STATE_DONE);
	sstring_destroy(&ss);

	return true;
}
char *
http_servlet_tmpl_func_get_header(struct tmpl_ctx *ctx,
	char **errmsgp, int ac, char **av)
{
	struct http_servlet_tmpl_arg *const arg = tmpl_ctx_get_arg(ctx);
	const char *const mtype = tmpl_ctx_get_mtype(ctx);
	const char *hval;

	if (ac != 2) {
		errno = EINVAL;
		return (NULL);
	}
	if ((hval = http_request_get_header(arg->req, av[1])) == NULL)
		hval = "";
	return (STRDUP(mtype, hval));
}
Пример #4
0
static gboolean get_base64_header(HttpRequest *req, gchar *name, gchar **value)
{
	gchar *header;
	gchar *tmp;

	header = http_request_get_header(req, name);
	if (header == NULL)
		return TRUE;


	tmp = mbb_base64_decode(header);
	if (tmp == NULL) {
		mbb_log_lvl(MBB_LOG_HTTP, "header %s has invalid value", name);
		return FALSE;
	}

	*value = tmp;
	return TRUE;
}
Пример #5
0
static gboolean process_http_body(struct http_thread_env *hte, HttpRequest *req)
{
	guint clen = 0;
	gchar *value;

	value = http_request_get_header(req, HTTP_CONTENT_LENGTH);
	if (value == NULL) {
		push_http_msg(hte, MBB_MSG_HEADER_MISSED, HTTP_CONTENT_LENGTH);
		return FALSE;
	}

	if (var_conv_uint(value, &clen) == FALSE) {
		push_http_error_msg(hte,
			"invalid header '%s: %s'", HTTP_CONTENT_LENGTH, value
		);
		return FALSE;
	}

	if (clen) {
		gsize n;

		req->body = g_malloc(clen + 1);
		req->body[clen] = '\0';

		if ((n = fread(req->body, 1, clen, hte->fp)) != (gsize) clen) {
			push_http_error_msg(hte,
				"http body incomplete: recv %d, must be %d",
				n, clen
			);
			return FALSE;
		}

		mbb_log_lvl(MBB_LOG_HTTP, "body: %s", req->body);
	}

	return TRUE;
}
Пример #6
0
static void
conn_request(void *ptr, http_request_t *request, http_response_t **response)
{
    const char realm[] = "airplay";
    raop_conn_t *conn = ptr;
    raop_t *raop = conn->raop;

    http_response_t *res;
    const char *method;
    const char *cseq;
    const char *challenge;
    int require_auth = 0;

    method = http_request_get_method(request);
    cseq = http_request_get_header(request, "CSeq");
    if (!method || !cseq) {
        return;
    }

    res = http_response_init("RTSP/1.0", 200, "OK");

    /* We need authorization for everything else than OPTIONS request */
    if (strcmp(method, "OPTIONS") != 0 && strlen(raop->password)) {
        const char *authorization;

        authorization = http_request_get_header(request, "Authorization");
        if (authorization) {
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Our nonce: %s", conn->nonce);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Authorization: %s", authorization);
        }
        if (!digest_is_valid(realm, raop->password, conn->nonce, method, http_request_get_url(request), authorization)) {
            char *authstr;
            int authstrlen;

            /* Allocate the authenticate string */
            authstrlen = sizeof("Digest realm=\"\", nonce=\"\"") + sizeof(realm) + sizeof(conn->nonce) + 1;
            authstr = malloc(authstrlen);

            /* Concatenate the authenticate string */
            memset(authstr, 0, authstrlen);
            strcat(authstr, "Digest realm=\"");
            strcat(authstr, realm);
            strcat(authstr, "\", nonce=\"");
            strcat(authstr, conn->nonce);
            strcat(authstr, "\"");

            /* Construct a new response */
            require_auth = 1;
            http_response_destroy(res);
            res = http_response_init("RTSP/1.0", 401, "Unauthorized");
            http_response_add_header(res, "WWW-Authenticate", authstr);
            free(authstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Authentication unsuccessful, sending Unauthorized");
        } else {
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Authentication successful!");
        }
    }

    http_response_add_header(res, "CSeq", cseq);
    http_response_add_header(res, "Apple-Jack-Status", "connected; type=analog");

    challenge = http_request_get_header(request, "Apple-Challenge");
    if (!require_auth && challenge) {
        char signature[MAX_SIGNATURE_LEN];

        memset(signature, 0, sizeof(signature));
        rsakey_sign(raop->rsakey, signature, sizeof(signature), challenge,
                    conn->local, conn->locallen, raop->hwaddr, raop->hwaddrlen);
        http_response_add_header(res, "Apple-Response", signature);

        logger_log(conn->raop->logger, LOGGER_DEBUG, "Got challenge: %s", challenge);
        logger_log(conn->raop->logger, LOGGER_DEBUG, "Got response: %s", signature);
    }

    if (require_auth) {
        /* Do nothing in case of authentication request */
    } else if (!strcmp(method, "OPTIONS")) {
        http_response_add_header(res, "Public", "ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER");
    } else if (!strcmp(method, "ANNOUNCE")) {
        const char *data;
        int datalen;

        unsigned char aeskey[16];
        unsigned char aesiv[16];
        int aeskeylen, aesivlen;

        data = http_request_get_data(request, &datalen);
        if (data) {
            sdp_t *sdp;
            const char *remotestr, *rtpmapstr, *fmtpstr, *aeskeystr, *aesivstr;

            sdp = sdp_init(data, datalen);
            remotestr = sdp_get_connection(sdp);
            rtpmapstr = sdp_get_rtpmap(sdp);
            fmtpstr = sdp_get_fmtp(sdp);
            aeskeystr = sdp_get_rsaaeskey(sdp);
            aesivstr = sdp_get_aesiv(sdp);

            logger_log(conn->raop->logger, LOGGER_DEBUG, "connection: %s", remotestr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "rtpmap: %s", rtpmapstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "fmtp: %s", fmtpstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "rsaaeskey: %s", aeskeystr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "aesiv: %s", aesivstr);

            aeskeylen = rsakey_decrypt(raop->rsakey, aeskey, sizeof(aeskey), aeskeystr);
            aesivlen = rsakey_parseiv(raop->rsakey, aesiv, sizeof(aesiv), aesivstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "aeskeylen: %d", aeskeylen);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "aesivlen: %d", aesivlen);

            if (conn->raop_rtp) {
                /* This should never happen */
                raop_rtp_destroy(conn->raop_rtp);
                conn->raop_rtp = NULL;
            }
            conn->raop_rtp = raop_rtp_init(raop->logger, &raop->callbacks, remotestr, rtpmapstr, fmtpstr, aeskey, aesiv);
            if (!conn->raop_rtp) {
                logger_log(conn->raop->logger, LOGGER_ERR, "Error initializing the audio decoder");
                http_response_set_disconnect(res, 1);
            }
            sdp_destroy(sdp);
        }
    } else if (!strcmp(method, "SETUP")) {
        unsigned short remote_cport=0, remote_tport=0;
        unsigned short cport=0, tport=0, dport=0;
        const char *transport;
        char buffer[1024];
        int use_udp;
        const char *dacp_id;
        const char *active_remote_header;

        dacp_id = http_request_get_header(request, "DACP-ID");
        active_remote_header = http_request_get_header(request, "Active-Remote");

        if (dacp_id && active_remote_header) {
            logger_log(conn->raop->logger, LOGGER_DEBUG, "DACP-ID: %s", dacp_id);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Active-Remote: %s", active_remote_header);
            if (conn->raop_rtp) {
                raop_rtp_remote_control_id(conn->raop_rtp, dacp_id, active_remote_header);
            }
        }

        transport = http_request_get_header(request, "Transport");
        assert(transport);

        logger_log(conn->raop->logger, LOGGER_INFO, "Transport: %s", transport);
        use_udp = strncmp(transport, "RTP/AVP/TCP", 11);
        if (use_udp) {
            char *original, *current, *tmpstr;

            current = original = strdup(transport);
            if (original) {
                while ((tmpstr = utils_strsep(&current, ";")) != NULL) {
                    unsigned short value;
                    int ret;

                    ret = sscanf(tmpstr, "control_port=%hu", &value);
                    if (ret == 1) {
                        logger_log(conn->raop->logger, LOGGER_DEBUG, "Found remote control port: %hu", value);
                        remote_cport = value;
                    }
                    ret = sscanf(tmpstr, "timing_port=%hu", &value);
                    if (ret == 1) {
                        logger_log(conn->raop->logger, LOGGER_DEBUG, "Found remote timing port: %hu", value);
                        remote_tport = value;
                    }
                }
            }
            free(original);
        }
        if (conn->raop_rtp) {
            raop_rtp_start(conn->raop_rtp, use_udp, remote_cport, remote_tport, &cport, &tport, &dport);
        } else {
            logger_log(conn->raop->logger, LOGGER_ERR, "RAOP not initialized at SETUP, playing will fail!");
            http_response_set_disconnect(res, 1);
        }

        memset(buffer, 0, sizeof(buffer));
        if (use_udp) {
            snprintf(buffer, sizeof(buffer)-1,
                     "RTP/AVP/UDP;unicast;mode=record;timing_port=%hu;events;control_port=%hu;server_port=%hu",
                     tport, cport, dport);
        } else {
            snprintf(buffer, sizeof(buffer)-1,
                     "RTP/AVP/TCP;unicast;interleaved=0-1;mode=record;server_port=%u",
                     dport);
        }
        logger_log(conn->raop->logger, LOGGER_INFO, "Responding with %s", buffer);
        http_response_add_header(res, "Transport", buffer);
        http_response_add_header(res, "Session", "DEADBEEF");
    } else if (!strcmp(method, "SET_PARAMETER")) {
        const char *content_type;
        const char *data;
        int datalen;

        content_type = http_request_get_header(request, "Content-Type");
        data = http_request_get_data(request, &datalen);
        if (!strcmp(content_type, "text/parameters")) {
            char *datastr;
            datastr = calloc(1, datalen+1);
            if (data && datastr && conn->raop_rtp) {
                memcpy(datastr, data, datalen);
                if (!strncmp(datastr, "volume: ", 8)) {
                    float vol = 0.0;
                    sscanf(datastr+8, "%f", &vol);
                    raop_rtp_set_volume(conn->raop_rtp, vol);
                } else if (!strncmp(datastr, "progress: ", 10)) {
                    unsigned int start, curr, end;
                    sscanf(datastr+10, "%u/%u/%u", &start, &curr, &end);
                    raop_rtp_set_progress(conn->raop_rtp, start, curr, end);
                }
            } else if (!conn->raop_rtp) {
                logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER");
            }
            free(datastr);
        } else if (!strcmp(content_type, "image/jpeg") || !strcmp(content_type, "image/png")) {
            logger_log(conn->raop->logger, LOGGER_INFO, "Got image data of %d bytes", datalen);
            if (conn->raop_rtp) {
                raop_rtp_set_coverart(conn->raop_rtp, data, datalen);
            } else {
                logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER coverart");
            }
        } else if (!strcmp(content_type, "application/x-dmap-tagged")) {
            logger_log(conn->raop->logger, LOGGER_INFO, "Got metadata of %d bytes", datalen);
            if (conn->raop_rtp) {
                raop_rtp_set_metadata(conn->raop_rtp, data, datalen);
            } else {
                logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER metadata");
            }
        }
    } else if (!strcmp(method, "FLUSH")) {
        const char *rtpinfo;
        int next_seq = -1;

        rtpinfo = http_request_get_header(request, "RTP-Info");
        if (rtpinfo) {
            logger_log(conn->raop->logger, LOGGER_INFO, "Flush with RTP-Info: %s", rtpinfo);
            if (!strncmp(rtpinfo, "seq=", 4)) {
                next_seq = strtol(rtpinfo+4, NULL, 10);
            }
        }
        if (conn->raop_rtp) {
            raop_rtp_flush(conn->raop_rtp, next_seq);
        } else {
            logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at FLUSH");
        }
    } else if (!strcmp(method, "TEARDOWN")) {
        http_response_add_header(res, "Connection", "close");
        if (conn->raop_rtp) {
            /* Destroy our RTP session */
            raop_rtp_stop(conn->raop_rtp);
            raop_rtp_destroy(conn->raop_rtp);
            conn->raop_rtp = NULL;
        }
    }
    http_response_finish(res, NULL, 0);

    logger_log(conn->raop->logger, LOGGER_DEBUG, "Handled request %s with URL %s", method, http_request_get_url(request));
    *response = res;
}
Пример #7
0
/*
 * Read in multi-part MIME data, and call the handler for each part.
 *
 * Returns the number of parts successfully read, or the ones
 * complement of that number if the handler aborted.
 */
int
http_request_get_mime_multiparts(struct http_request *req,
	http_mime_handler_t *handler, void *arg)
{
	const char *hval;
	FILE *fp = NULL;
	char boundary[256];
	char buf[256];
	char *tokctx;
	FILE *input;
	int nparts;
	char *s;

	/* Get POST input stream */
	if ((input = http_request_get_input(req)) == NULL)
		return (~0);

	/* Get boundary string */
	if ((hval = http_request_get_header(req,
	      HTTP_HEADER_CONTENT_TYPE)) == NULL
	    || strlen(hval) > sizeof(buf) - 1)
		goto bogus;
	strlcpy(buf, hval, sizeof(buf));
	if ((s = strchr(buf, ';')) == NULL)
		goto bogus;
	*s++ = '\0';
	if (strcasecmp(buf, HTTP_CTYPE_MULTIPART_FORMDATA) != 0)
		goto bogus;
	if ((s = strtok_r(s, " \t;=", &tokctx)) == NULL
	    || strcasecmp(s, "boundary") != 0
	    || (s = strtok_r(NULL, " \t;=", &tokctx)) == NULL) {
bogus:		errno = EINVAL;
		return (~0);
	}
	snprintf(boundary, sizeof(boundary), "\r\n--%s", s);

	/* Read up through the initial boundary string */
	if ((fp = boundary_fopen(input, boundary + 2, 0)) == NULL)
		return (~0);
	while (fgets(buf, sizeof(buf), fp) != NULL)
		;
	if (ferror(fp)) {
		fclose(fp);
		return (~0);
	}
	fclose(fp);

	/* Read in each part */
	for (nparts = 0; 1; nparts++) {
		struct mime_part part;
		int ch;
		int r;

		/* We just saw a boundary; see if it was the last one */
		if ((ch = getc(input)) == '-')
			return (nparts);
		if (ch != '\r' || getc(input) != '\n') {
			errno = EFTYPE;
			break;
		}

		/* Get stream for the next part only */
		if ((fp = boundary_fopen(input, boundary, 0)) == NULL)
			break;

		/* Read in the next part's headers */
		memset(&part, 0, sizeof(part));
		if ((part.head = _http_head_new()) == NULL) {
			fclose(fp);
			break;
		}
		if (_http_head_read_headers(part.head, fp) == -1) {
			_http_head_free(&part.head);
			fclose(fp);
			break;
		}

		/* Invoke the handler */
		r = (*handler)(arg, &part, fp);

		/* Read any data not read by handler */
		while (fgets(buf, sizeof(buf), fp) != NULL)
			;

		/* Clean up */
		_http_head_free(&part.head);
		fclose(fp);

		/* If handler aborted, stop */
		if (r != 0)
			break;
	}

	/* There was an error */
	return (~nparts);
}
Пример #8
0
Файл: raop.c Проект: viettd56/SA
static void
conn_request(void *ptr, http_request_t *request, http_response_t **response)
{
    const char realm[] = "airplay";
    raop_conn_t *conn = ptr;
    raop_t *raop = conn->raop;

    http_response_t *res;
    const char *method;
    const char *url;
    const char *cseq;
    const char *challenge;
    int require_auth = 0;
    char *data = NULL;
    int length_res = 0;

    method = http_request_get_method(request);
    url = http_request_get_url(request);
    cseq = http_request_get_header(request, "CSeq");
    if (!method || !cseq)
    {
        return;
    }
    printf("-----------------\n");

    res = http_response_init("RTSP/1.0", 200, "OK");

    /* We need authorization for everything else than OPTIONS request */
    if (strcmp(method, "OPTIONS") != 0 && strlen(raop->password))
    {
        const char *authorization;

        authorization = http_request_get_header(request, "Authorization");
        if (authorization)
        {
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Our nonce: %s", conn->nonce);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Authorization: %s", authorization);
        }
        if (!digest_is_valid(realm, raop->password, conn->nonce, method, http_request_get_url(request), authorization))
        {
            char *authstr;
            int authstrlen;

            /* Allocate the authenticate string */
            authstrlen = sizeof("Digest realm=\"\", nonce=\"\"") + sizeof(realm) + sizeof(conn->nonce) + 1;
            authstr = malloc(authstrlen);

            /* Concatenate the authenticate string */
            memset(authstr, 0, authstrlen);
            strcat(authstr, "Digest realm=\"");
            strcat(authstr, realm);
            strcat(authstr, "\", nonce=\"");
            strcat(authstr, conn->nonce);
            strcat(authstr, "\"");

            /* Construct a new response */
            require_auth = 1;
            http_response_destroy(res);
            res = http_response_init("RTSP/1.0", 401, "Unauthorized");
            http_response_add_header(res, "WWW-Authenticate", authstr);
            free(authstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Authentication unsuccessful, sending Unauthorized");
        }
        else
        {
            logger_log(conn->raop->logger, LOGGER_DEBUG, "Authentication successful!");
        }
    }

    http_response_add_header(res, "CSeq", cseq);
    // http_response_add_header(res, "Apple-Jack-Status", "connected; type=analog");

    challenge = http_request_get_header(request, "Apple-Challenge");
    if (!require_auth && challenge)
    {
        char signature[MAX_SIGNATURE_LEN];

        memset(signature, 0, sizeof(signature));
        rsakey_sign(raop->rsakey, signature, sizeof(signature), challenge,
                    conn->local, conn->locallen, raop->hwaddr, raop->hwaddrlen);
        http_response_add_header(res, "Apple-Response", signature);

        logger_log(conn->raop->logger, LOGGER_DEBUG, "Got challenge: %s", challenge);
        logger_log(conn->raop->logger, LOGGER_DEBUG, "Got response: %s", signature);
    }

    if (require_auth)
    {
        /* Do nothing in case of authentication request */
    }
    else if (!strcmp(method, "OPTIONS"))
    {
        http_response_add_header(res, "Public", "ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER");
    }
    else if (!strcmp(method, "ANNOUNCE"))
    {
        const char *data;
        int datalen;

        unsigned char aeskey[16];
        unsigned char aesiv[16];
        int aeskeylen, aesivlen;

        data = http_request_get_data(request, &datalen);
        if (data)
        {
            sdp_t *sdp;
            const char *remotestr, *rtpmapstr, *fmtpstr, *aeskeystr, *aesivstr;

            sdp = sdp_init(data, datalen);
            remotestr = sdp_get_connection(sdp);
            rtpmapstr = sdp_get_rtpmap(sdp);
            fmtpstr = sdp_get_fmtp(sdp);
            aeskeystr = sdp_get_rsaaeskey(sdp);
            aesivstr = sdp_get_aesiv(sdp);

            logger_log(conn->raop->logger, LOGGER_DEBUG, "connection: %s", remotestr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "rtpmap: %s", rtpmapstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "fmtp: %s", fmtpstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "rsaaeskey: %s", aeskeystr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "aesiv: %s", aesivstr);

            aeskeylen = rsakey_decrypt(raop->rsakey, aeskey, sizeof(aeskey), aeskeystr);
            aesivlen = rsakey_parseiv(raop->rsakey, aesiv, sizeof(aesiv), aesivstr);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "aeskeylen: %d", aeskeylen);
            logger_log(conn->raop->logger, LOGGER_DEBUG, "aesivlen: %d", aesivlen);

            if (conn->raop_rtp)
            {
                /* This should never happen */
                raop_rtp_destroy(conn->raop_rtp);
                conn->raop_rtp = NULL;
            }
            conn->raop_rtp = raop_rtp_init(raop->logger, &raop->callbacks, remotestr, rtpmapstr, fmtpstr, aeskey, aesiv);
            if (!conn->raop_rtp)
            {
                logger_log(conn->raop->logger, LOGGER_ERR, "Error initializing the audio decoder");
                http_response_set_disconnect(res, 1);
            }
            sdp_destroy(sdp);
        }
    }
    else if (!strcmp(method, "SETUP"))
    {
        unsigned short remote_cport = 0, remote_tport = 0;
        unsigned short cport = 0, tport = 0, dport = 0;
        const char *transport;
        char buffer[1024];
        int use_udp;

        transport = http_request_get_header(request, "Transport");
        assert(transport);

        logger_log(conn->raop->logger, LOGGER_INFO, "Transport: %s", transport);
        use_udp = strncmp(transport, "RTP/AVP/TCP", 11);
        if (use_udp)
        {
            char *original, *current, *tmpstr;

            current = original = strdup(transport);
            if (original)
            {
                while ((tmpstr = utils_strsep(&current, ";")) != NULL)
                {
                    unsigned short value;
                    int ret;

                    ret = sscanf(tmpstr, "control_port=%hu", &value);
                    if (ret == 1)
                    {
                        logger_log(conn->raop->logger, LOGGER_DEBUG, "Found remote control port: %hu", value);
                        remote_cport = value;
                    }
                    ret = sscanf(tmpstr, "timing_port=%hu", &value);
                    if (ret == 1)
                    {
                        logger_log(conn->raop->logger, LOGGER_DEBUG, "Found remote timing port: %hu", value);
                        remote_tport = value;
                    }
                }
            }
            free(original);
        }
        if (conn->raop_rtp)
        {
            raop_rtp_start(conn->raop_rtp, use_udp, remote_cport, remote_tport, &cport, &tport, &dport);
        }
        else
        {
            logger_log(conn->raop->logger, LOGGER_ERR, "RAOP not initialized at SETUP, playing will fail!");
            http_response_set_disconnect(res, 1);
        }

        memset(buffer, 0, sizeof(buffer));
        if (use_udp)
        {
            snprintf(buffer, sizeof(buffer) - 1,
                     "RTP/AVP/UDP;unicast;mode=record;timing_port=%hu;events;control_port=%hu;server_port=%hu",
                     tport, cport, dport);
        }
        else
        {
            snprintf(buffer, sizeof(buffer) - 1,
                     "RTP/AVP/TCP;unicast;interleaved=0-1;mode=record;server_port=%u",
                     dport);
        }
        logger_log(conn->raop->logger, LOGGER_INFO, "Responding with %s", buffer);
        http_response_add_header(res, "Transport", buffer);
        http_response_add_header(res, "Session", "DEADBEEF");
    }
    else if (!strcmp(method, "SET_PARAMETER"))
    {
        const char *content_type;
        const char *data;
        int datalen;

        content_type = http_request_get_header(request, "Content-Type");
        data = http_request_get_data(request, &datalen);
        if (!strcmp(content_type, "text/parameters"))
        {
            char *datastr;
            datastr = calloc(1, datalen + 1);
            if (data && datastr && conn->raop_rtp)
            {
                memcpy(datastr, data, datalen);
                if (!strncmp(datastr, "volume: ", 8))
                {
                    float vol = 0.0;
                    sscanf(datastr + 8, "%f", &vol);
                    raop_rtp_set_volume(conn->raop_rtp, vol);
                }
            }
            else if (!conn->raop_rtp)
            {
                logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER volume");
            }
            free(datastr);
        }
        else if (!strcmp(content_type, "image/jpeg"))
        {
            logger_log(conn->raop->logger, LOGGER_INFO, "Got image data of %d bytes", datalen);
            if (conn->raop_rtp)
            {
                raop_rtp_set_coverart(conn->raop_rtp, data, datalen);
            }
            else
            {
                logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER coverart");
            }
        }
        else if (!strcmp(content_type, "application/x-dmap-tagged"))
        {
            logger_log(conn->raop->logger, LOGGER_INFO, "Got metadata of %d bytes", datalen);
            if (conn->raop_rtp)
            {
                raop_rtp_set_metadata(conn->raop_rtp, data, datalen);
            }
            else
            {
                logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER metadata");
            }
        }
    }
    else if (!strcmp(method, "FLUSH"))
    {
        const char *rtpinfo;
        int next_seq = -1;

        rtpinfo = http_request_get_header(request, "RTP-Info");
        if (rtpinfo)
        {
            logger_log(conn->raop->logger, LOGGER_INFO, "Flush with RTP-Info: %s", rtpinfo);
            if (!strncmp(rtpinfo, "seq=", 4))
            {
                next_seq = strtol(rtpinfo + 4, NULL, 10);
            }
        }
        if (conn->raop_rtp)
        {
            raop_rtp_flush(conn->raop_rtp, next_seq);
        }
        else
        {
            logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at FLUSH");
        }
    }
    else if (!strcmp(method, "TEARDOWN"))
    {
        http_response_add_header(res, "Connection", "close");
        if (conn->raop_rtp)
        {
            /* Destroy our RTP session */
            raop_rtp_stop(conn->raop_rtp);
            raop_rtp_destroy(conn->raop_rtp);
            conn->raop_rtp = NULL;
        }
    }
    else if (!strcmp(method, "POST"))
    {
        if (!strcmp(url, "/fp-setup"))
        {
            printf("POST fp-setup\n");

            int datalen;

            uint8_t fply_1[] __attribute__((unused)) =
            {
                0x46, 0x50, 0x4c, 0x59, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x02, 0xbb
            };
            // 2 1 2 -> 130 : 02 02 xxx
            uint8_t fply_2[] =
            {
                0x46, 0x50, 0x4c, 0x59, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x82,
                0x02, 0x02, 0x2f, 0x7b, 0x69, 0xe6, 0xb2, 0x7e, 0xbb, 0xf0, 0x68, 0x5f, 0x98, 0x54, 0x7f, 0x37,
                0xce, 0xcf, 0x87, 0x06, 0x99, 0x6e, 0x7e, 0x6b, 0x0f, 0xb2, 0xfa, 0x71, 0x20, 0x53, 0xe3, 0x94,
                0x83, 0xda, 0x22, 0xc7, 0x83, 0xa0, 0x72, 0x40, 0x4d, 0xdd, 0x41, 0xaa, 0x3d, 0x4c, 0x6e, 0x30,
                0x22, 0x55, 0xaa, 0xa2, 0xda, 0x1e, 0xb4, 0x77, 0x83, 0x8c, 0x79, 0xd5, 0x65, 0x17, 0xc3, 0xfa,
                0x01, 0x54, 0x33, 0x9e, 0xe3, 0x82, 0x9f, 0x30, 0xf0, 0xa4, 0x8f, 0x76, 0xdf, 0x77, 0x11, 0x7e,
                0x56, 0x9e, 0xf3, 0x95, 0xe8, 0xe2, 0x13, 0xb3, 0x1e, 0xb6, 0x70, 0xec, 0x5a, 0x8a, 0xf2, 0x6a,
                0xfc, 0xbc, 0x89, 0x31, 0xe6, 0x7e, 0xe8, 0xb9, 0xc5, 0xf2, 0xc7, 0x1d, 0x78, 0xf3, 0xef, 0x8d,
                0x61, 0xf7, 0x3b, 0xcc, 0x17, 0xc3, 0x40, 0x23, 0x52, 0x4a, 0x8b, 0x9c, 0xb1, 0x75, 0x05, 0x66,
                0xe6, 0xb3
            };
            // 2 1 3 -> 152
            // 4 : 02 8f 1a 9c
            // 128 : xxx
            // 20 : 5b ed 04 ed c3 cd 5f e6 a8 28 90 3b 42 58 15 cb 74 7d ee 85
            uint8_t fply_3[] __attribute__((unused)) =
            {
                0x46, 0x50, 0x4c, 0x59, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x98, 0x02, 0x8f,
                0x1a, 0x9c, 0x6e, 0x73, 0xd2, 0xfa, 0x62, 0xb2, 0xb2, 0x07, 0x6f, 0x52, 0x5f, 0xe5, 0x72, 0xa5,
                0xac, 0x4d, 0x19, 0xb4, 0x7c, 0xd8, 0x07, 0x1e, 0xdb, 0xbc, 0x98, 0xae, 0x7e, 0x4b, 0xb4, 0xb7,
                0x2a, 0x7b, 0x5e, 0x2b, 0x8a, 0xde, 0x94, 0x4b, 0x1d, 0x59, 0xdf, 0x46, 0x45, 0xa3, 0xeb, 0xe2,
                0x6d, 0xa2, 0x83, 0xf5, 0x06, 0x53, 0x8f, 0x76, 0xe7, 0xd3, 0x68, 0x3c, 0xeb, 0x1f, 0x80, 0x0e,
                0x68, 0x9e, 0x27, 0xfc, 0x47, 0xbe, 0x3d, 0x8f, 0x73, 0xaf, 0xa1, 0x64, 0x39, 0xf7, 0xa8, 0xf7,
                0xc2, 0xc8, 0xb0, 0x20, 0x0c, 0x85, 0xd6, 0xae, 0xb7, 0xb2, 0xd4, 0x25, 0x96, 0x77, 0x91, 0xf8,
                0x83, 0x68, 0x10, 0xa1, 0xa9, 0x15, 0x4a, 0xa3, 0x37, 0x8c, 0xb7, 0xb9, 0x89, 0xbf, 0x86, 0x6e,
                0xfb, 0x95, 0x41, 0xff, 0x03, 0x57, 0x61, 0x05, 0x00, 0x73, 0xcc, 0x06, 0x7e, 0x4f, 0xc7, 0x96,
                0xae, 0xba, 0x5b, 0xed, 0x04, 0xed, 0xc3, 0xcd, 0x5f, 0xe6, 0xa8, 0x28, 0x90, 0x3b, 0x42, 0x58,
                0x15, 0xcb, 0x74, 0x7d, 0xee, 0x85
            };
            // 2 1 4 -> 20 : 5b ed 04 ed c3 cd 5f e6 a8 28 90 3b 42 58 15 cb 74 7d ee 85
            uint8_t fply_4[] =
            {
                0x46, 0x50, 0x4c, 0x59, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x5b,
                0xed, 0x04, 0xed, 0xc3, 0xcd, 0x5f, 0xe6, 0xa8, 0x28, 0x90, 0x3b, 0x42, 0x58, 0x15, 0xcb, 0x74,
                0x7d, 0xee, 0x85
            };

            uint8_t fply_header[12];
            char *content = http_request_get_data(request, &datalen);
            memcpy(fply_header, content, sizeof(fply_header));
            char payload[datalen - sizeof(fply_header)];
            memcpy(payload, content + sizeof(fply_header), datalen - sizeof(fply_header));



            if (fply_header[6] == 1)
            {
                printf("fh == 1\n");

                memcpy(fply_2 + 13, content + 14, 1);
                data = (char *) malloc(sizeof(fply_2));
                length_res = sizeof(fply_2);
                memcpy(data, fply_2, sizeof(fply_2));
            }
            else if (fply_header[6] == 3)
            {
                printf("fh == 3\n");

                data = (char *) malloc(12 + 20);
                length_res = 12 + 20;
                memcpy(data, fply_4, 12);
                memcpy(data + 12, payload + datalen - 20, 20);
            }

            http_response_add_header(res, "Content-Type", "application/octet-stream");
            http_response_add_header(res, "Server", "AirTunes/110.92");
        }
    }
/*
 * Run template servlet
 */
static int
http_servlet_tmpl_run(struct http_servlet *servlet,
	struct http_request *req, struct http_response *resp)
{
	struct tmpl_private *const priv = servlet->arg;
	struct http_servlet_tmpl_info *const info = &priv->info;
	struct http_servlet_tmpl_tinfo *const tinfo = &priv->info.tinfo;
	struct tmpl_instance *this = NULL;
	FILE *output = NULL;
	const char *hval;
	struct stat sb;
	int num_errors;
	int r;

	/* Construct per-instance state */
	if ((this = MALLOC(MEM_TYPE, sizeof(*this))) == NULL) {
		(*info->logger)(LOG_ERR, "%s: %s: %s",
		    __FUNCTION__, "malloc", strerror(errno));
		return (-1);
	}
	memset(this, 0, sizeof(*this));
	this->priv = priv;

	/* Grab lock to avoid race with http_servlet_tmpl_destroy() */
	r = pthread_rwlock_rdlock(&priv->lock);
	assert(r == 0);

	/* Push cleanup hook in case thread gets canceled */
	pthread_cleanup_push(http_servlet_tmpl_run_cleanup, this);

	/* Get servlet output stream (buffered) */
	if ((output = http_response_get_output(resp, 1)) == NULL) {
		(*info->logger)(LOG_ERR, "can't get template output: %s",
		    strerror(errno));
		goto fail_errno;
	}

	/* Set MIME type */
	if (info->mime_type == NULL) {
		http_response_set_header(resp, 0,
		    HTTP_HEADER_CONTENT_TYPE, "text/html; charset=iso-8859-1");
	} else {
		http_response_set_header(resp, 0,
		    HTTP_HEADER_CONTENT_TYPE, "%s", info->mime_type);
		if (info->mime_encoding != NULL) {
			http_response_set_header(resp,
			0, HTTP_HEADER_CONTENT_ENCODING,
			    "%s", info->mime_encoding);
		}
	}

	/* Assume servlet output is not cachable */
	http_response_set_header(resp, 1, HTTP_HEADER_PRAGMA, "no-cache");
	http_response_set_header(resp, 0,
	    HTTP_HEADER_CACHE_CONTROL, "no-cache");

	/* Get modification timestamp of the template file */
	if (stat(info->path, &sb) == -1) {
		(*info->logger)(LOG_ERR, "%s: %s: %s",
		    __FUNCTION__, info->path, strerror(errno));
		memset(&sb.st_mtime, 0, sizeof(sb.st_mtime));
	}

	/* Invalidate cached template if template file has changed */
	if (priv->tmpl != NULL
	    && memcmp(&sb.st_mtime, &priv->mtime, sizeof(priv->mtime)) != 0) {
		(*info->logger)(LOG_INFO,
		    "template \"%s\" was updated", info->path);
		tmpl_destroy(&priv->tmpl);
	}

	/* Do we need to (re)parse the template? */
	if (priv->tmpl == NULL) {

		/* Parse template file */
		if ((priv->tmpl = tmpl_create_mmap(info->path,
		    &num_errors, tinfo->mtype)) == NULL) {
			(*info->logger)(LOG_ERR,
			    "can't create template from \"%s\": %s",
			    info->path, strerror(errno));
			goto fail_errno;
		}

		/* Check for an error from tmpl_create() */
		if (priv->tmpl == NULL) {
			(*info->logger)(LOG_ERR,
			    "can't create \"%s\" template: %s", info->path,
			    strerror(errno));
			goto fail_errno;
		}

		/* Warn if there were any parse errors */
		if (num_errors != 0) {
			(*info->logger)(LOG_WARNING,
			    "%d parse error%s in template \"%s\"",
			    num_errors, num_errors == 1 ? "" : "s",
			    info->path);
		}

		/* Update last modified time */
		memcpy(&priv->mtime, &sb.st_mtime, sizeof(priv->mtime));
	}

	/* Read URL-encoded form data if this is a normal POST */
	if (strcmp(http_request_get_method(req), HTTP_METHOD_POST) == 0
	    && (hval = http_request_get_header(req,
	      HTTP_HEADER_CONTENT_TYPE)) != NULL
	    && strcasecmp(hval, HTTP_CTYPE_FORM_URLENCODED) == 0) {
		if (http_request_read_url_encoded_values(req) == -1) {
			(*info->logger)(LOG_ERR,
			    "error reading %s data for \"%s\" template: %s",
			    HTTP_METHOD_POST, info->path, strerror(errno));
			goto fail_errno;
		}
	}

	/* Fill in handler function cookie */
	this->targ.arg = info->tinfo.arg;
	this->targ.req = req;
	this->targ.resp = resp;

	/* Create tmpl execution context */
	if ((this->ctx = tmpl_ctx_create(&this->targ,
	    tinfo->mtype, tinfo->handler, tinfo->errfmtr)) == NULL) {
		(*info->logger)(LOG_ERR, "%s: %s: %s",
		    __FUNCTION__, "tmpl_ctx_create", strerror(errno));
		goto fail_errno;
	}

	/* Execute template */
	if (tmpl_execute(priv->tmpl, this->ctx, output, tinfo->flags) == -1) {
		(*info->logger)(LOG_ERR, "can't execute \"%s\" template: %s",
		    info->path, strerror(errno));
		goto fail_errno;
	}

	/* OK */
	goto done;

fail_errno:
	/* Fail with appropriate error response */
	http_response_send_errno_error(resp);

done:
	/* Done */
	if (output != NULL)
		fclose(output);
	pthread_cleanup_pop(1);
	return (1);
}