Précédent   Forum des professionnels en informatique > Bases de données > Oracle > PL/SQL
PL/SQL Forum d'entraide sur le PL/SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 23/11/2011, 12h32   #1
Invité de passage
 
Homme franck guindeuil
Développeur informatique
Inscription : novembre 2011
Messages : 2
Détails du profil
Informations personnelles :
Nom : Homme franck guindeuil
Localisation : France, Hauts de Seine (Île de France)

Informations professionnelles :
Activité : Développeur informatique
Secteur : Administration - Collectivité locale

Informations forums :
Inscription : novembre 2011
Messages : 2
Points : 0
Points : 0
Par défaut UTL_HTTP envoi de fichier via requete POST (HTTP500 - Stream ended unexpectedly)

J'obtiens l'erreur 500 Internal Server Error : Processing of multipart/form-data request failed. Stream ended unexpectedly quand j'envoie une requete POST sur un serveur apache tomcat 5.5 qui se trouve dans un autre service (je n'ai pas la main directement dessus)
L'objectif est d'envoyer un fichier KML (c'est un fichier XML)
J'aimerai savoir si mon code est bon et si ma requete http finale est bonne
et surtout pourquoi j'obtiens l'erreur (mon fichier fait un peu moins de 300Ko)
est ce que le problème peut venir du serveur sur lequel je n'ai pas la main? du genre maxPostSize? http://www.developpez.net/forums/d94...-unexpectedly/


voici ci dessous mon code

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
 
--
-- Envoi d'un KML dans l'extranet des consignations via POST
-- 
PROCEDURE Envoyer_KML
	( pNomFic		 VARCHAR2
	, pDirectoryId   VARCHAR2
    , pRecordId      VARCHAR2
    )
IS
  vContenu       	VARCHAR2(4000); --contiendra le debut du contenu le content de la requete HTTP
  vPostText     	CLOB;
  vRequest      	UTL_HTTP.REQ;
  vResponse     	UTL_HTTP.RESP;
  vResponseText 	VARCHAR2(4000);
  vErrorText    	VARCHAR2(2000);
  vReponseWsOk      VARCHAR2(7) 	:='{"Id":%';
 
  vContentLenght   integer:=0;     --contiendra la taille de la requete HTTP
 
  vLeBfile			BFILE;
  vLen 				NUMBER := dbms_lob.lobmaxsize;
  vNum 				NUMBER ;
  vSrc_off 			PLS_INTEGER := 1 ;
  vDst_off 			PLS_INTEGER := 1 ;
  vLangctx 			NUMBER := dbms_lob.default_lang_ctx ;
  vWarn 			NUMBER;
 
  nStart 			NUMBER := 1;
  nEnd 				NUMBER := 32000;
  nClobLength 		NUMBER;
  vChunkData 		VARCHAR2(32000);
  nLength 			NUMBER := 32000;
 
  vFrontiere 		VARCHAR2(60) := 'FfGg0x75';
BEGIN
 
	--*****************************************
	--lecture du fichier dans un clob
	--*****************************************
 
	--creation du fichier temporaire
	dbms_lob.createtemporary( vPostText, TRUE ) ;
 
	--initialisation du clob au debut de la requete
	vContenu :=             '--' || vFrontiere || CHR(13) || CHR(10) || 'content-disposition: form-data; name="directoryId"' || CHR(13) || CHR(10) || CHR(13) || CHR(10) || pDirectoryId || CHR(13) || CHR(10) ;
	vContenu := vContenu || '--' || vFrontiere || CHR(13) || CHR(10) || 'content-disposition: form-data; name="recordId"' || CHR(13) || CHR(10) || CHR(13) || CHR(10) || pRecordId || CHR(13) || CHR(10) ;
	vContenu := vContenu || '--' || vFrontiere || CHR(13) || CHR(10) || 'content-disposition: form-data; name="14"; filename="' || pNomFic || '"' || CHR(13) || CHR(10) ;
	vContenu := vContenu || 'Content-Type: text/xml' || CHR(13) || CHR(10) ;
	vContenu := vContenu || 'Content-Transfer-Encoding: UTF-8'  || CHR(13) || CHR(10)  || CHR(13) || CHR(10) ;
	dbms_lob.WRITE(vPostText, LENGTH(vContenu), 1, vContenu);
 
	--ouverture du fichier
	vLeBfile := BFILENAME( 'KML_FILES', pNomFic );
 	dbms_lob.fileopen(vLeBfile, dbms_lob.file_readonly);
 
	--reglage du debut de la destination à la fin du CLOB
	vDst_off := LENGTH(vContenu)+1;
 
	DBMS_LOB.LOADCLOBFROMFILE (
		vPostText,            -- CLOB de destination
        vLeBfile,             -- Pointeur fichier en entrée
        vLen,                 -- Nombre d'octets à lire
        vDst_off,             -- Position destination de départ
        vSrc_off,             -- Position source de départ
        dbms_lob.default_csid,-- CSID
        vLangctx,             -- Contexte langue
        vWarn);               -- Message d'avertissement
	dbms_lob.fileclose(vLeBfile);
 
	--écriture de la derniere frontiere (fin du fichier)
	dbms_lob.writeappend(vPostText, length(vFrontiere)+4, '--' || vFrontiere || '--' );
 
	--suppression des caractères accentués pour avoir une taille équivalente au nombre de caractères
	--plus tard je compterai doubles ces caractères dans le content-lenght
    vPostText := dfn_clobReplace(vPostText,'é','e');
	vPostText := dfn_clobReplace(vPostText,'è','e');
	vPostText := dfn_clobReplace(vPostText,'à','a');
	vPostText := dfn_clobReplace(vPostText,'ô','o');
	vPostText := dfn_clobReplace(vPostText,'ç','c');
	vPostText := dfn_clobReplace(vPostText,'°','0');
 
	DBMS_OUTPUT.PUT_LINE('Content lenght = ' || dbms_lob.getLength(vPostText));
 
	--*****************************************
	--envoi du fichier 
	--*****************************************
	--réglage du proxy  
	utl_http.set_proxy(proxy=>ADRESSE_PROXY);  
 
	--création de l'objet requête
	vRequest := UTL_HTTP.BEGIN_REQUEST
        ( url 			=> ADRESSE_WS_KML  
        , METHOD 		=> 'POST'
        , http_version	=> 'HTTP/1.1'
        );
 
	--réglage de la requete au format UTF-8
	UTL_HTTP.SET_BODY_CHARSET
		(r 			=> vRequest
	    ,charset 	=> CHARSET_EMISSION);
 
	--le header Content-Type
	UTL_HTTP.SET_HEADER
		( r     => vRequest
		, NAME  => 'Content-Type'
		, VALUE => 'multipart/form-data, boundary=' || vFrontiere
		);
 
	--le header Content-Length
    UTL_HTTP.SET_HEADER
		( r     => vRequest
	 	, NAME  => 'Content-Length'
	    , VALUE => (dbms_lob.getLength(vPostText)+1)
		);
 
	nClobLength := dbms_lob.getLength(vPostText);
 
	--
	--ecrire le corps de la requete en faisant une boucle 
	--
	LOOP
		IF nEnd > nClobLength then
		  nEnd := nClobLength;
		  nLength := nEnd - nStart+1;
		end IF;
		DBMS_OUTPUT.PUT_LINE ('nEnd:' || nEnd || ' nClobLength:' || nClobLength || ' nLength:' || nLength);
		vChunkData := NULL;
		vChunkData := DBMS_LOB.SUBSTR(vPostText, nLength, nStart);
		UTL_HTTP.WRITE_TEXT ( vRequest, vChunkData );
		DBMS_OUTPUT.PUT_LINE ( vChunkData );
		IF nEnd = nClobLength then
		  exit;
		end IF;
		nStart := nEnd ;
		nEnd := nStart + 32000;
	END LOOP;
 
	--envoi de la requete et récupération de la réponse
	vResponse := UTL_HTTP.GET_RESPONSE(vRequest);
 
	--*************************************************************
	--analyse de la réponse
	--*************************************************************
	IF vResponse.status_code = STATUS_OK THEN
		--reponse = OK 
		--la réponse est au format ISO-8859-1	
		UTL_HTTP.SET_BODY_CHARSET
			(r 			=> vResponse
			,charset 	=> CHARSET_RECEPTION);
		--lire la réponse
		UTL_HTTP.READ_TEXT(vResponse, vResponseText);
		--si reponse NOK mettre son contenu dans la variable d'erreur
		IF vResponseText NOT LIKE vReponseWsOk THEN
			vErrorText := vResponseText;
			DBMS_OUTPUT.PUT_LINE ('vResponseText NOT LIKE vReponseWsOk');
			DBMS_OUTPUT.PUT_LINE (vResponseText || vResponse.status_code);
		ELSE
			DBMS_OUTPUT.PUT_LINE ('vResponseText LIKE vReponseWsOk');
		END IF;
    ELSE --reponse = NOK
		--mettre le code et la raison dans la variable d'erreur
		DBMS_OUTPUT.PUT_LINE ('status:'||vResponse.status_code||' reason:'||vResponse.reason_phrase);
		vErrorText := 'status:'||vResponse.status_code||' reason:'||vResponse.reason_phrase;
    END IF;
    --fermer la réponse libérer les CLOB
    UTL_HTTP.END_RESPONSE(vResponse);
    dbms_lob.freetemporary(vPostText);
 
 
    --si la variable d'erreur n'est pas vide : journaliser
    IF vErrorText IS NOT NULL THEN
		Pkg_Journal.INSERT_LOG_INTERNAL_ERROR (SQLCODE, 'création impossible de la consignation n°' || ' ErrorText=' || vErrorText, 'PKG_EXTRANET_DES_CONSIGNATIONS-Envoyer_KML');
    END IF;
 
END Envoyer_KML;


Voici ci dessous la reqete qui est vraiment envoyée : je l'ai récupérée de wireshark que j'ai installé sur le serveur de base de données

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 
POST http://r55-signalement.rec.fin.URL/signalement/jsp/site/rest/directory/record/ HTTP/1.1
Host: r55-signalement.rec.fin.URL
Content-Type: multipart/form-DATA, boundary=FfGg0x75
Content-Length: 232040
Connection: close
 
--FfGg0x75
content-disposition: form-DATA; name="directoryId"
 
2
--FfGg0x75
content-disposition: form-DATA; name="recordId"
 
293
--FfGg0x75
content-disposition: form-DATA; name="14"; filename="consignations.kml"
Content-Type: text/xml
Content-Transfer-Encoding: UTF-8
 
<?xml version="1.0" encoding="utf-8" ?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document><Folder><name>consignation</name>
<Schema name="consignation" id="consignation">
	<SimpleField name="Name" type="string"></SimpleField>
	<SimpleField name="Description" type="string"></SimpleField>
	<SimpleField name="NUM_CONSIGNATION" type="string"></SimpleField>
	<SimpleField name="AFFICHAGE" type="string"></SimpleField>
</Schema>
  <Placemark>
	<name>Consignation n0 : 172434</name>
	<description>Localisation : Intersection rue Rambuteau rue Mondetour&lt;br /&gt;Date de debut : 2003/10/31 &lt;br /&gt;Date de fin : 2010/01/01&lt;br /&gt;Commentaire : </description>
	<Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style>
	<ExtendedData><SchemaData schemaUrl="#consignation">
		<SimpleData name="NUM_CONSIGNATION">Consignation n0 : 172434</SimpleData>
		<SimpleData name="AFFICHAGE">Localisation : Intersection rue Rambuteau rue Mondetour&lt;br /&gt;Date de debut : 2003/10/31 &lt;br /&gt;Date de fin : 2010/01/01&lt;br /&gt;Commentaire : </SimpleData>
	</SchemaData></ExtendedData>
      <LineString><coordinates>2.348370159975013,48.862451839376206,43.198869185522199 2.348299417217526,48.862431612632072,43.19891501031816 2.348206598165612,48.862428483136988,43.198971983976662 2.347824984890921,48.862516288185496,43.199192680418491 2.347980158816752,48.862828231251981,43.199056162498891 2.348360837512066,48.862818023987202,43.198825596831739 2.348430759427624,48.862822162791609,43.198782439343631 2.348570473785997,48.862860188214363,43.198692202568054</coordinates></LineString>
  </Placemark>
  ...150 placemarks entre les deux...
  <Placemark>
	<name>Consignation n0 : 410833</name>
	<description>Localisation : test FG BR&lt;br /&gt;Date de debut : 2011/10/28 &lt;br /&gt;Date de fin : 2011/10/31&lt;br /&gt;Commentaire : test FG BR</description>
	<Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style>
	<ExtendedData><SchemaData schemaUrl="#consignation">
		<SimpleData name="NUM_CONSIGNATION">Consignation n0 : 410833</SimpleData>
		<SimpleData name="AFFICHAGE">Localisation : test FG BR&lt;br /&gt;Date de debut : 2011/10/28 &lt;br /&gt;Date de fin : 2011/10/31&lt;br /&gt;Commentaire : test FG BR</SimpleData>
	</SchemaData></ExtendedData>
      <LineString><coordinates>2.329534197301053,48.827828272982103,43.215011136606336 2.330051766530076,48.827826148421778,43.214695536531508</coordinates></LineString>
  </Placemark>
</Folder></Document></kml>
--FfGg0x75--

Voici ci dessous la réponse du serveur

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 
HTTP/1.1 500 Internal Server Error
Via: 1.1 RES-DM-PXINT-S2
Connection: close
Proxy-Connection: close
Content-Length: 3021
Date: Tue, 22 Nov 2011 16:54:35 GMT
Content-Type: text/html;charset=utf-8
Server: Apache/2.0.52 (Red Hat)
 
<html><head><title>Apache Tomcat/5.5.23 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Exception report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server encountered an internal error () that prevented it from fulfilling this request.</u></p><p><b>exception</b> <pre>javax.servlet.ServletException: Unkown error occured during the upload
	Debut.URL.portal.web.upload.UploadFilter.doFilter(UploadFilter.java:218)
	Debut.URL.portal.web.upload.DosGuardFilter.doFilter(DosGuardFilter.java:126)
	Debut.URL.portal.web.encoding.EncodingFilter.doFilter(EncodingFilter.java:86)
</pre></p><p><b>root cause</b> <pre>org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-DATA request failed. Stream ended unexpectedly
	org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:371)
	org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
	Debut.URL.portal.web.upload.UploadFilter.doFilter(UploadFilter.java:157)
	Debut.URL.portal.web.upload.DosGuardFilter.doFilter(DosGuardFilter.java:126)
	Debut.URL.portal.web.encoding.EncodingFilter.doFilter(EncodingFilter.java:86)
</pre></p><p><b>root cause</b> <pre>org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
	org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:982)
	org.apache.commons.fileupload.MultipartStream$ItemInputStream.READ(MultipartStream.java:886)
	java.io.InputStream.READ(InputStream.java:89)
	org.apache.commons.fileupload.util.Streams.copy(Streams.java:96)
	org.apache.commons.fileupload.util.Streams.copy(Streams.java:66)
	org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:366)
	org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
	Debut.URL.portal.web.upload.UploadFilter.doFilter(UploadFilter.java:157)
	Debut.URL.portal.web.upload.DosGuardFilter.doFilter(DosGuardFilter.java:126)
	Debut.URL.portal.web.encoding.EncodingFilter.doFilter(EncodingFilter.java:86)
</pre></p><p><b>note</b> <u>The full stack trace of the root cause IS available IN the Apache Tomcat/5.5.23 logs.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/5.5.23</h3></body></html>



Mais en fait je me pose une question qui est peut être plus importante :
Est ce une bonne architecture? sachant que la demande initiale indique que l'envoi du fichier doit se faire sur un clic de souris dans une application. Ce qui entrainerai que la procédure serait appelée sur un trigger (create, update ou delete).
Faire tout ceci via un trigger : cela me heurte un peu quelque part...
Peut être qu'une autre solution serait de
-1- mettre à jour une valeur dans la base à chaque create, update ou delete
-2- faire un job qui crée le fichier et l'envoie (le job tournerai tous les quarts d'heure)

D'avance merci pour l'aide que vous pourrez m'apporter.
franck guindeuil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 16h53   #2
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 313
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 313
Points : 5 819
Points : 5 819
Citation:
Envoyé par franck guindeuil Voir le message
...Faire tout ceci via un trigger : cela me heurte un peu quelque part...
Peut être qu'une autre solution serait de
-1- mettre à jour une valeur dans la base à chaque create, update ou delete
-2- faire un job qui crée le fichier et l'envoie (le job tournerai tous les quarts d'heure)

D'avance merci pour l'aide que vous pourrez m'apporter.
La solution classique à ce type de problème est de créer dans le trigger un job via dbms_job qui va exécuter une procédure stockée qui devrait envoyer le fichier via utl_http.
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/11/2011, 10h29   #3
Invité de passage
 
Homme franck guindeuil
Développeur informatique
Inscription : novembre 2011
Messages : 2
Détails du profil
Informations personnelles :
Nom : Homme franck guindeuil
Localisation : France, Hauts de Seine (Île de France)

Informations professionnelles :
Activité : Développeur informatique
Secteur : Administration - Collectivité locale

Informations forums :
Inscription : novembre 2011
Messages : 2
Points : 0
Points : 0
Merci pour votre réponse
Comme ceci?


création d un [TRIGGER]
qui appelle [PKG_EXTRANET_DES_CONSIGNATIONS.Creer_et_envoyer_KMLS] Code ci dessous
qui appelle [JOB CREER_KML_CONSIGNATION] code ci dessous
qui appelle [PKG_EXTRANET_DES_CONSIGNATIONS.Envoyer_KMLS] (code ci dessus)


Code :
1
2
3
4
5
6
7
8
9
10
11
 
PROCEDURE Creer_et_envoyer_KMLS(toto Varchar2)
IS PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
	--les consignations
	DBMS_SCHEDULER.RUN_JOB (job_name => 'CREER_KML_CONSIGNATION',use_current_session => FALSE);
	Envoyer_KML ('consignations.kml','2', '29');
	--les br
	DBMS_SCHEDULER.RUN_JOB (job_name => 'CREER_KML_BR',use_current_session => FALSE);
	--Envoyer_KML ('br.kml','2', '29');
END Creer_et_envoyer_KMLS;
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
    job_name             => 'CREER_KML_CONSIGNATION',
    job_type             => 'EXECUTABLE',
    number_of_arguments  => 3,
    job_action           => 'C:\windows\system32\cmd.exe',
    enabled              => FALSE,
    auto_drop            => FALSE,
	comments        	 => 'job qui appelle ogr2ogr pour créer le fichier kml des consignations');
    DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('CREER_KML_CONSIGNATION',1,'/c');
    DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('CREER_KML_CONSIGNATION',2,'ogr2ogr.exe');
    DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('CREER_KML_CONSIGNATION',3,'-f "KML" -s_srs "EPSG:27561" -t_srs "EPSG:3857" "E:\KML\consignations.kml" "OCI:tig5/tig5@FORM" -sql "select * from v_EDC_KML_CONSIGNATION order by asset_id" -nln consignation -select num_consignation,affichage -dsco namefield=num_consignation -dsco descriptionfield=affichage');
    dbms_scheduler.enable('CREER_KML_CONSIGNATION'); 
END;
Je pense qu'en fait le problème vient du serveur auquel je n'ai pas accès.
Je vais contacter mon homologue du service d'à coté (mais bon envoyer les KML n'est pas encore sa priorité) cela risque de prendre du temps.

-FG-
franck guindeuil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/11/2011, 16h03   #4
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 313
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 313
Points : 5 819
Points : 5 819
En gros c'est comme ça sauf qu'il faut employer DBMS_JOB et ne pas utiliser une transaction autonome.
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 14h38.


 
 
 
 
Partenaires

Hébergement Web