// forme à partir d'un lien et du contexte (origin_fil et origin_adr d'où il est tiré) adr et fil // [adr et fil sont des buffers de 1ko] // 0 : ok // -1 : erreur // -2 : protocole non supporté (ftp) int ident_url_relatif(const char *lien,const char* origin_adr,const char* origin_fil,char* adr,char* fil) { int ok=0; int scheme=0; adr[0]='\0'; fil[0]='\0'; //effacer buffers // lien non vide! if (strnotempty(lien)==0) return -1; // erreur! // Scheme? { const char* a=lien; while (isalpha((unsigned char)*a)) a++; if (*a == ':') scheme=1; } // filtrer les parazites (mailto & cie) // scheme+authority (//) if ( (strfield(lien,"http://")) // scheme+// || (strfield(lien,"file://")) // scheme+// || (strncmp(lien,"//",2)==0) // // sans scheme (-> default) ) { if (ident_url_absolute(lien,adr,fil)==-1) { ok=-1; // erreur URL } } else if (strfield(lien,"ftp://")) { // Note: ftp:foobar.gif is not valid if (ftp_available()) { // ftp supporté if (ident_url_absolute(lien,adr,fil)==-1) { ok=-1; // erreur URL } } else { ok=-2; // non supporté } #if HTS_USEMMS } else if (strfield(lien,"mms://")) { if (ident_url_absolute(lien,adr,fil)==-1) { ok=-1; // erreur URL } #endif #if HTS_USEOPENSSL } else if (strfield(lien,"https://")) { if (SSL_is_available) { // Note: ftp:foobar.gif is not valid if (ident_url_absolute(lien,adr,fil)==-1) { ok=-1; // erreur URL } } else { ok=-1; } #endif } else if ((scheme) && ( (!strfield(lien,"http:")) && (!strfield(lien,"https:")) && (!strfield(lien,"ftp:")) #if HTS_USEMMS && (!strfield(lien,"mms:")) #endif )) { ok=-1; // unknown scheme } else { // c'est un lien relatif // On forme l'URL complète à partie de l'url actuelle // et du chemin actuel si besoin est. // copier adresse if (((int) strlen(origin_adr)<HTS_URLMAXSIZE) && ((int) strlen(origin_fil)<HTS_URLMAXSIZE) && ((int) strlen(lien)<HTS_URLMAXSIZE)) { /* patch scheme if necessary */ if (strfield(lien,"http:")) { lien+=5; strcpybuff(adr, jump_protocol(origin_adr)); // même adresse ; protocole vide (http) } else if (strfield(lien,"https:")) { lien+=6; strcpybuff(adr, "https://"); // même adresse forcée en https strcatbuff(adr, jump_protocol(origin_adr)); } else if (strfield(lien,"ftp:")) { lien+=4; strcpybuff(adr, "ftp://"); // même adresse forcée en ftp strcatbuff(adr, jump_protocol(origin_adr)); #if HTS_USEMMS } else if (strfield(lien,"mms:")) { lien+=4; strcpybuff(adr, "mms://"); // même adresse forcée en ftp strcatbuff(adr, jump_protocol(origin_adr)); #endif } else { strcpybuff(adr,origin_adr); // même adresse ; et même éventuel protocole } if (*lien!='/') { // sinon c'est un lien absolu if (*lien == '\0') { strcpybuff(fil,origin_fil); } else if (*lien == '?') { // example: a href="?page=2" char* a; strcpybuff(fil,origin_fil); a=strchr(fil,'?'); if (a) *a='\0'; strcatbuff(fil,lien); } else { const char *a=strchr(origin_fil,'?'); if (a == NULL) a=origin_fil+strlen(origin_fil); while((*a!='/') && ( a > origin_fil) ) a--; if (*a=='/') { // ok on a un '/' if ( (((int) (a - origin_fil))+1+strlen(lien)) < HTS_URLMAXSIZE) { // copier chemin strncpy(fil,origin_fil,((int) (a - origin_fil))+1); *(fil + ((int) (a - origin_fil))+1)='\0'; // copier chemin relatif if (((int) strlen(fil)+(int) strlen(lien)) < HTS_URLMAXSIZE) { strcatbuff(fil,lien + ((*lien=='/')?1:0) ); // simplifier url pour les ../ fil_simplifie(fil); } else ok=-1; // erreur } else { // erreur ok=-1; // erreur URL } } else { // erreur ok=-1; // erreur URL } } } else { // chemin absolu // copier chemin directement strcatbuff(fil,lien); fil_simplifie(fil); } // *lien!='/' } else ok=-1; } // test news: etc. // case insensitive pour adresse { char *a=jump_identification(adr); while(*a) { if ((*a>='A') && (*a<='Z')) *a+='a'-'A'; a++; } } return ok; }
// forme à partir d'un lien et du contexte (origin_fil et origin_adr d'où il est tiré) adr et fil // [adr et fil sont des buffers de 1ko] // 0 : ok // -1 : erreur // -2 : protocole non supporté (ftp) int ident_url_relatif(const char *lien, const char *origin_adr, const char *origin_fil, lien_adrfil* const adrfil) { int ok = 0; int scheme = 0; assertf(adrfil != NULL); adrfil->adr[0] = '\0'; adrfil->fil[0] = '\0'; //effacer buffers // lien non vide! if (strnotempty(lien) == 0) return -1; // erreur! // Scheme? { const char *a = lien; while(isalpha((unsigned char) *a)) a++; if (*a == ':') scheme = 1; } // filtrer les parazites (mailto & cie) // scheme+authority (//) if ((strfield(lien, "http://")) // scheme+// || (strfield(lien, "file://")) // scheme+// || (strncmp(lien, "//", 2) == 0) // // sans scheme (-> default) ) { if (ident_url_absolute(lien, adrfil) == -1) { ok = -1; // erreur URL } } else if (strfield(lien, "ftp://")) { // Note: ftp:foobar.gif is not valid if (ftp_available()) { // ftp supporté if (ident_url_absolute(lien, adrfil) == -1) { ok = -1; // erreur URL } } else { ok = -2; // non supporté } #if HTS_USEOPENSSL } else if (strfield(lien, "https://")) { // Note: ftp:foobar.gif is not valid if (ident_url_absolute(lien, adrfil) == -1) { ok = -1; // erreur URL } #endif } else if ((scheme) && ((!strfield(lien, "http:")) && (!strfield(lien, "https:")) && (!strfield(lien, "ftp:")) )) { ok = -1; // unknown scheme } else { // c'est un lien relatif // On forme l'URL complète à partie de l'url actuelle // et du chemin actuel si besoin est. // sanity check if (origin_adr == NULL || origin_fil == NULL || *origin_adr == '\0' || *origin_fil == '\0') { return -1; } // copier adresse if (((int) strlen(origin_adr) < HTS_URLMAXSIZE) && ((int) strlen(origin_fil) < HTS_URLMAXSIZE) && ((int) strlen(lien) < HTS_URLMAXSIZE)) { /* patch scheme if necessary */ if (strfield(lien, "http:")) { lien += 5; strcpybuff(adrfil->adr, jump_protocol_const(origin_adr)); // même adresse ; protocole vide (http) } else if (strfield(lien, "https:")) { lien += 6; strcpybuff(adrfil->adr, "https://"); // même adresse forcée en https strcatbuff(adrfil->adr, jump_protocol_const(origin_adr)); } else if (strfield(lien, "ftp:")) { lien += 4; strcpybuff(adrfil->adr, "ftp://"); // même adresse forcée en ftp strcatbuff(adrfil->adr, jump_protocol_const(origin_adr)); } else { strcpybuff(adrfil->adr, origin_adr); // même adresse ; et même éventuel protocole } if (*lien != '/') { // sinon c'est un lien absolu if (*lien == '\0') { strcpybuff(adrfil->fil, origin_fil); } else if (*lien == '?') { // example: a href="?page=2" char *a; strcpybuff(adrfil->fil, origin_fil); a = strchr(adrfil->fil, '?'); if (a) *a = '\0'; strcatbuff(adrfil->fil, lien); } else { const char *a = strchr(origin_fil, '?'); if (a == NULL) a = origin_fil + strlen(origin_fil); while((*a != '/') && (a > origin_fil)) a--; if (*a == '/') { // ok on a un '/' if ((((int) (a - origin_fil)) + 1 + strlen(lien)) < HTS_URLMAXSIZE) { // copier chemin strncpy(adrfil->fil, origin_fil, ((int) (a - origin_fil)) + 1); *(adrfil->fil + ((int) (a - origin_fil)) + 1) = '\0'; // copier chemin relatif if (((int) strlen(adrfil->fil) + (int) strlen(lien)) < HTS_URLMAXSIZE) { strcatbuff(adrfil->fil, lien + ((*lien == '/') ? 1 : 0)); // simplifier url pour les ../ fil_simplifie(adrfil->fil); } else ok = -1; // erreur } else { // erreur ok = -1; // erreur URL } } else { // erreur ok = -1; // erreur URL } } } else { // chemin absolu // copier chemin directement strcatbuff(adrfil->fil, lien); fil_simplifie(adrfil->fil); } // *lien!='/' } else ok = -1; } // test news: etc. // case insensitive pour adresse { char *a = jump_identification(adrfil->adr); while(*a) { if ((*a >= 'A') && (*a <= 'Z')) *a += 'a' - 'A'; a++; } } // IDNA / RFC 3492 (Punycode) handling for HTTP(s) if (!link_has_authority(adrfil->adr) || strfield(adrfil->adr, "https:")) { char *const a = jump_identification(adrfil->adr); // Non-ASCII characters (theorically forbidden, but browsers are lenient) if (!hts_isStringAscii(a, strlen(a))) { char *const idna = hts_convertStringUTF8ToIDNA(a, strlen(a)); if (idna != NULL) { if (strlen(idna) < HTS_URLMAXSIZE) { strcpybuff(a, idna); } free(idna); } } } return ok; }