+ yaz_log(YLOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+ m_session_str, reduce, bw_total, pdu_total,
+ m_bw_max, m_pdu_max);
+
+ m_timeout_mode = timeout_reduce;
+ m_timeout_gdu = gdu;
+ timeout(reduce); // call us reduce seconds later
+ }
+ else
+ recv_GDU_normal(gdu);
+}
+
+void Yaz_Proxy::recv_GDU_more(bool normal)
+{
+ GDU *g;
+ if (normal && m_timeout_mode == timeout_busy)
+ m_timeout_mode = timeout_normal;
+ while (m_timeout_mode == timeout_normal && (g = m_in_queue.dequeue()))
+ {
+ m_timeout_mode = timeout_busy;
+ recv_GDU_reduce(g);
+ }
+}
+
+void Yaz_Proxy::recv_GDU_normal(GDU *gdu)
+{
+ Z_GDU *apdu = 0;
+ gdu->move_away_gdu(odr_decode(), &apdu);
+ delete gdu;
+
+ if (apdu->which == Z_GDU_Z3950)
+ handle_incoming_Z_PDU(apdu->u.z3950);
+ else if (apdu->which == Z_GDU_HTTP_Request)
+ handle_incoming_HTTP(apdu->u.HTTP_Request);
+}
+
+void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)
+{
+ if (m_max_record_retrieve)
+ {
+ if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ if (pr->numberOfRecordsRequested &&
+ *pr->numberOfRecordsRequested > m_max_record_retrieve)
+ *pr->numberOfRecordsRequested = m_max_record_retrieve;
+ }
+ }
+}
+
+void Yaz_Proxy::handle_charset_lang_negotiation(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_initRequest)
+ {
+ if (m_initRequest_options &&
+ !ODR_MASK_GET(m_initRequest_options, Z_Options_negotiationModel) &&
+ (m_proxy_negotiation_charset || m_proxy_negotiation_lang))
+ {
+ // There is no negotiation proposal from
+ // client's side. OK. The proxy negotiation
+ // in use, only.
+ Z_InitRequest *initRequest = apdu->u.initRequest;
+ Z_OtherInformation **otherInfo;
+ Z_OtherInformationUnit *oi;
+ get_otherInfoAPDU(apdu, &otherInfo);
+ oi = update_otherInformation(otherInfo, 1, NULL, 0, 0);
+ if (oi)
+ {
+ ODR_MASK_SET(initRequest->options,
+ Z_Options_negotiationModel);
+ oi->which = Z_OtherInfo_externallyDefinedInfo;
+ oi->information.externallyDefinedInfo =
+ yaz_set_proposal_charneg(odr_encode(),
+ (const char**)&m_proxy_negotiation_charset,
+ m_proxy_negotiation_charset ? 1:0,
+ (const char**)&m_proxy_negotiation_lang,
+ m_proxy_negotiation_lang ? 1:0,
+ 1);
+ }
+ }
+ else if (m_initRequest_options &&
+ ODR_MASK_GET(m_initRequest_options,
+ Z_Options_negotiationModel) &&
+ m_charset_converter->get_target_query_charset())
+ {
+ yaz_log(YLOG_LOG, "%sManaged charset negotiation: charset=%s",
+ m_session_str,
+ m_charset_converter->get_target_query_charset());
+ Z_InitRequest *initRequest = apdu->u.initRequest;
+ Z_CharSetandLanguageNegotiation *negotiation =
+ yaz_get_charneg_record (initRequest->otherInfo);
+ if (negotiation &&
+ negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
+ {
+ NMEM nmem = nmem_create();
+ char **charsets = 0;
+ int num_charsets = 0;
+ char **langs = 0;
+ int num_langs = 0;
+ int selected = 0;
+ yaz_get_proposal_charneg (nmem, negotiation,
+ &charsets, &num_charsets,
+ &langs, &num_langs, &selected);
+ int i;
+ for (i = 0; i<num_charsets; i++)
+ yaz_log(YLOG_LOG, "%scharset %s", m_session_str,
+ charsets[i]);
+ for (i = 0; i<num_langs; i++)
+ yaz_log(YLOG_LOG, "%slang %s", m_session_str,
+ langs[i]);
+
+ const char *t_charset =
+ m_charset_converter->get_target_query_charset();
+ // sweep through charsets and pick the first supported
+ // conversion
+ for (i = 0; i<num_charsets; i++)
+ {
+ const char *c_charset = charsets[i];
+ if (!odr_set_charset(odr_decode(), t_charset, c_charset))
+ break;
+ }
+ if (i != num_charsets)
+ {
+ // got one .. set up ODR for reverse direction
+ const char *c_charset = charsets[i];
+ odr_set_charset(odr_encode(), c_charset, t_charset);
+ m_charset_converter->set_client_query_charset(c_charset);
+ m_charset_converter->set_client_charset_selected(selected);
+ }
+ nmem_destroy(nmem);
+ ODR_MASK_CLEAR(m_initRequest_options,
+ Z_Options_negotiationModel);
+ yaz_del_charneg_record(&initRequest->otherInfo);
+ }
+ else
+ {
+ yaz_log(YLOG_WARN, "%sUnable to decode charset package",
+ m_session_str);
+ }
+ }
+ else if (m_charset_converter->get_target_query_charset() &&
+ m_proxy_negotiation_default_charset)
+ {
+ m_charset_converter->
+ set_client_query_charset(m_proxy_negotiation_default_charset);
+ }
+ }
+ else if (apdu->which == Z_APDU_initResponse)
+ {
+ Z_InitResponse *initResponse = apdu->u.initResponse;
+ Z_OtherInformation **otherInfo;
+ get_otherInfoAPDU(apdu, &otherInfo);
+
+ Z_CharSetandLanguageNegotiation *charneg = 0;
+
+ if (otherInfo && *otherInfo &&
+ ODR_MASK_GET(initResponse->options, Z_Options_negotiationModel)
+ && (charneg = yaz_get_charneg_record(*otherInfo)))
+ {
+ char *charset = 0;
+ char *lang = 0;
+ int selected = 0;
+
+ yaz_get_response_charneg(m_referenceId_mem, charneg,
+ &charset, &lang, &selected);
+
+ yaz_log(YLOG_LOG, "%sAccepted charset - '%s' and lang - '%s'",
+ m_session_str, (charset)?charset:"none", (lang)?lang:"none");
+
+ if (m_initRequest_options &&
+ ODR_MASK_GET(m_initRequest_options, Z_Options_negotiationModel))
+ {
+ yaz_log(YLOG_LOG, "%sClient's negotiation record in use",
+ m_session_str);
+ }
+ else if (m_proxy_negotiation_charset || m_proxy_negotiation_lang)
+ {
+ // negotiation-charset, negotiation-lang
+ // elements of config file in use.
+
+ yaz_log(YLOG_LOG, "%sProxy's negotiation record in use",
+ m_session_str);
+
+ // clear negotiation option.
+ ODR_MASK_CLEAR(initResponse->options, Z_Options_negotiationModel);
+
+ // Delete negotiation (charneg-3) entry.
+ yaz_del_charneg_record(otherInfo);
+ }
+ }
+ else
+ {
+ if (m_proxy_negotiation_charset || m_proxy_negotiation_lang)
+ {
+ yaz_log(YLOG_LOG, "%sTarget did not honor negotiation",
+ m_session_str);
+ }
+ else if (m_charset_converter->get_client_query_charset())
+ {
+ Z_OtherInformation **otherInfo;
+ Z_OtherInformationUnit *oi;
+ get_otherInfoAPDU(apdu, &otherInfo);
+ oi = update_otherInformation(otherInfo, 1, NULL, 0, 0);
+ if (oi)
+ {
+ ODR_MASK_SET(initResponse->options,
+ Z_Options_negotiationModel);
+ if (m_initRequest_options)
+ ODR_MASK_SET(m_initRequest_options,
+ Z_Options_negotiationModel);
+
+ oi->which = Z_OtherInfo_externallyDefinedInfo;
+ oi->information.externallyDefinedInfo =
+ yaz_set_response_charneg(
+ odr_encode(),
+ m_charset_converter->get_client_query_charset(),
+ 0 /* no lang */,
+ m_charset_converter->get_client_charset_selected());
+ }
+ }
+ }