QByteArray HttpHeaders::getAsFirstParameter(const QByteArray &key) const { HttpHeaderParameters p = getAsParameters(key); if(p.isEmpty()) return QByteArray(); return p[0].first; }
Instruct Instruct::fromResponse(const HttpResponseData &response, bool *ok, QString *errorMessage) { HoldMode holdMode = NoHold; QList<Channel> channels; int timeout = -1; QList<QByteArray> exposeHeaders; QByteArray keepAliveData; int keepAliveTimeout = -1; QHash<QString, QString> meta; HttpResponseData newResponse; if(response.headers.contains("Grip-Hold")) { QByteArray gripHoldStr = response.headers.get("Grip-Hold"); if(gripHoldStr == "response") { holdMode = ResponseHold; } else if(gripHoldStr == "stream") { holdMode = StreamHold; } else { setError(ok, errorMessage, "Grip-Hold must be set to either 'response' or 'stream'"); return Instruct(); } } QList<HttpHeaderParameters> gripChannels = response.headers.getAllAsParameters("Grip-Channel"); foreach(const HttpHeaderParameters &gripChannel, gripChannels) { if(gripChannel.isEmpty()) { setError(ok, errorMessage, "failed to parse Grip-Channel"); return Instruct(); } Channel c; c.name = QString::fromUtf8(gripChannel[0].first); QByteArray param = gripChannel.get("prev-id"); if(!param.isNull()) c.prevId = QString::fromUtf8(param); for(int n = 1; n < gripChannel.count(); ++n) { const HttpHeaderParameter ¶m = gripChannel[n]; if(param.first == "filter") c.filters += QString::fromUtf8(param.second); } channels += c; } if(response.headers.contains("Grip-Timeout")) { bool x; timeout = response.headers.get("Grip-Timeout").toInt(&x); if(!x) { setError(ok, errorMessage, "failed to parse Grip-Timeout"); return Instruct(); } if(timeout < 0) { setError(ok, errorMessage, "Grip-Timeout has invalid value"); return Instruct(); } } exposeHeaders = response.headers.getAll("Grip-Expose-Headers"); HttpHeaderParameters keepAliveParams = response.headers.getAsParameters("Grip-Keep-Alive"); if(!keepAliveParams.isEmpty()) { QByteArray val = keepAliveParams[0].first; if(val.isEmpty()) { setError(ok, errorMessage, "Grip-Keep-Alive cannot be empty"); return Instruct(); } if(keepAliveParams.contains("timeout")) { bool x; keepAliveTimeout = keepAliveParams.get("timeout").toInt(&x); if(!x) { setError(ok, errorMessage, "failed to parse Grip-Keep-Alive timeout value"); return Instruct(); } if(keepAliveTimeout < 0) { setError(ok, errorMessage, "Grip-Keep-Alive timeout has invalid value"); return Instruct(); } } else { keepAliveTimeout = DEFAULT_RESPONSE_TIMEOUT; } QByteArray format = keepAliveParams.get("format"); if(format.isEmpty() || format == "raw") { keepAliveData = val; } else if(format == "cstring") { keepAliveData = unescape(val); if(keepAliveData.isNull()) { setError(ok, errorMessage, "failed to parse Grip-Keep-Alive cstring format"); return Instruct(); } } else if(format == "base64") { keepAliveData = QByteArray::fromBase64(val); } else { setError(ok, errorMessage, QString("no such Grip-Keep-Alive format '%1'").arg(QString::fromUtf8(format))); return Instruct(); } } QList<HttpHeaderParameters> metaParams = response.headers.getAllAsParameters("Grip-Set-Meta", HttpHeaders::ParseAllParameters); foreach(const HttpHeaderParameters &metaParam, metaParams) { if(metaParam.isEmpty()) { setError(ok, errorMessage, "Grip-Set-Meta cannot be empty"); return Instruct(); } QString key = QString::fromUtf8(metaParam[0].first); QString val = QString::fromUtf8(metaParam[0].second); meta[key] = val; } newResponse = response; QByteArray statusHeader = response.headers.get("Grip-Status"); if(!statusHeader.isEmpty()) { QByteArray codeStr; QByteArray reason; int at = statusHeader.indexOf(' '); if(at != -1) { codeStr = statusHeader.mid(0, at); reason = statusHeader.mid(at + 1); } else { codeStr = statusHeader; } bool _ok; newResponse.code = codeStr.toInt(&_ok); if(!_ok || newResponse.code < 0 || newResponse.code > 999) { setError(ok, errorMessage, "Grip-Status contains invalid status code"); return Instruct(); } newResponse.reason = reason; } QUrl nextLink; int nextLinkTimeout = -1; foreach(const HttpHeaderParameters ¶ms, response.headers.getAllAsParameters("Grip-Link")) { if(params.count() >= 2 && params.get("rel") == "next") { QByteArray linkParam = params[0].first; if(linkParam.length() <= 2 || linkParam[0] != '<' || linkParam[linkParam.length() - 1] != '>') { setError(ok, errorMessage, "failed to parse Grip-Link value"); return Instruct(); } nextLink = QUrl::fromEncoded(linkParam.mid(1, linkParam.length() - 2)); if(!nextLink.isValid()) { setError(ok, errorMessage, "Grip-Link contains invalid link"); return Instruct(); } if(params.contains("timeout")) { bool x; nextLinkTimeout = params.get("timeout").toInt(&x); if(!x) { setError(ok, errorMessage, "failed to parse Grip-Link timeout value"); return Instruct(); } if(nextLinkTimeout < 0) { setError(ok, errorMessage, "Grip-Link timeout has invalid value"); return Instruct(); } } else { nextLinkTimeout = DEFAULT_NEXTLINK_TIMEOUT; } } } newResponse.headers.clear(); foreach(const HttpHeader &h, response.headers) { // strip out grip headers if(qstrnicmp(h.first.data(), "Grip-", 5) == 0) continue; if(!exposeHeaders.isEmpty()) { bool found = false; foreach(const QByteArray &e, exposeHeaders) { if(qstricmp(e.data(), h.first.data()) == 0) { found = true; break; } } if(!found) continue; } newResponse.headers += HttpHeader(h.first, h.second); }