Developement d'un module d'extraction de fichier

Questions sur le développement d'Apache et de ses modules.

Modérateur : Modérateurs

nono44200
Nouveau membre
Messages : 1
Inscription : mer. 19 sept. 2012, 15:57

Developement d'un module d'extraction de fichier

Messagepar nono44200 » mer. 19 sept. 2012, 18:28

Bonjour,

Je m'appelle Arnaud et je suis nouveau sur ce forum. Je suis developpeur Java/J2ee et je travaille à Nantes.
Je suis actuellement en train de développer un module pour apache qui devra a terme me permettre d'extraire les fichiers contenus (input file) dans une requête http multipart/form-data.

J'ai pas mal avancé sur le sujet mais je suis bloqué par un problème qui est sans aucun doute lié à une compréhension partielle de l'api APR (Apache Portable Runtime) et notamment des concepts de brigade, bucket et filtres. J'ai parcouru pas mal de doc, tuto, code en Anglais mais je dois avouer que je ne maitrise pas encore bien le sujet. Pour arranger le tout, je suis débutant en langace C et je dois dire que cela fait bcp de concepts à appréhender d'un seul coup.

Venons-en au problème :
Dans le code j'utilise l'API apreq pour parser ma requête. Après quelques déboires concernant l'installation de cette librairie sur linux centos, j'arrive tout de même à parser ma requête et extraire le fichier.Le problème est que le module ne fonctionne qu'avec de petits fichiers qui font tout au plus quelques mégas.

http://httpd.apache.org/apreq/docs/liba ... 5fc8edf1fe

Sur des gros fichiers la consommation du serveur Apache monte en flèche jusqu'à consommer 100 % de la mémoire et de l'espace swap. Je suis contraint d'arrêter le service apache, voir même de redémarrer brutalement la machine.
Après quelques tests, je me suis aperçu que le problème de consommation mémoire provient de l'instruction apr_bucket_copy(e,&b);

Malheureusement, pour l'instant, je n'ai pas trouver d'autres solutions que d'utiliser cette instruction pour copier la donnée et la mettre dans la brigade de sortie bbout afin de passer les données au filtre suivant. Mon module ne doit pas altérer la requête d'origine. La requête doit ensuite être transmise à un serveur tiers en utilisant le mod_proxy d'apache qui joue uniquement le rôle de frontale dans l'archi logicielle.
L'objectif finale est donc d'extraire les données de la requête et de laisser la requête telle quelle pour qu'elle soit traiter par les filtres suivants comme s'il ne c'était rien passé. Or, si je ne fais pas cette copie ainsi que "INSERT_TAIL", à la fin du traitement l'appel de "ap_pass_brigade(f->next, bbout);" envoie au filtre suivant une brigade vide. Mais ces deux instructions consomment trop de ressources.

J'imagine que pour des personnes ayant déjà développé ce genre de module le problème est assez simple mais je vous avoue que cela fait plus de deux semaines que je suis bloqué ! Pourtant j'ai l'impression d'être si proche du but, ça fonctionne sur des petites requêtes et ca plante le serveur sur des plus grosses !

Si quelqu'un a une petite idée et pouvait me donner une piste à explorer ou une remarque quelconque me permettant d'avancer je serais ravi et très reconnaissant. Je suis ouvert à toute remarque ou critique sur le code. Je me doute que la qualité n'est pas au rendez-vous !!!

En vous remerciant par avance de m'avoir lu.

Bonne soirée.

Arnaud qui commence à désespérer !


Voici le code de mon input_filter
:

Code : Tout sélectionner

static apr_status_t upload_nuxeo_filter(ap_filter_t *f, apr_bucket_brigade *bbout, ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes) {

   upload_ctx* ctx = (upload_ctx*) f->ctx;
   
   if ((f->r->method_number != M_GET) && (f->r->method_number != M_POST)) {
      return HTTP_METHOD_NOT_ALLOWED;
   }

   if(f->r->method_number == M_POST)
   { 
      apreq_parser_function_t f_parser_function;
      f_parser_function = apreq_parser(MFD_ENCTYPE);
      apr_table_t* formd = apr_table_make(f->r->pool, APREQ_DEFAULT_NELTS);
      apr_table_t* filed = apr_table_make(f->r->pool, APREQ_DEFAULT_NELTS);
      const char *str;
      apr_size_t j,len = 0;
      apr_bucket  *e,*b;
      apr_status_t rv;

      /** Allocation of a structure used to iterate over  uploaded files and make writing treatments */
      swo_params_t* uploaded_files = apr_palloc(f->r->pool, sizeof(swo_params_t)) ;                       

      apr_bucket_brigade* bbin = apr_brigade_create(f->r->pool,f->r->connection->bucket_alloc);
      if (strcmp(f->r->method,"POST") == 0){
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "###### make parser ### START    ##########");
         apreq_parser_t * psr = apreq_parser_make(
            f->r->pool,
            f->r->connection->bucket_alloc,
            apr_table_get(f->r->headers_in,"Content-Type"),
            apreq_parser(apr_table_get(f->r->headers_in,"Content-Type")),
            0, /* FORCE TO SPOOL FILES */
            NUXEO_CACHE_DIR_PATH,
            NULL,
            NULL);                                 
         
         int s = APR_SUCCESS;
         int cptBrigade = 0;
         int cptBucket =0;
         
         while(s = ap_get_brigade(f->next, bbin, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN)== APR_SUCCESS)
         {
            cptBrigade++;
            // // Récupération des données pour le buffer de sortie (afin de transmettre la requete au filtre suivant !
            for(e = APR_BRIGADE_FIRST(bbin);
               e != APR_BRIGADE_SENTINEL(bbin);
               e =  APR_BUCKET_NEXT(e))
            {       
               cptBucket++;
               if (APR_BUCKET_IS_FLUSH(e))
               {
                  continue;
               }

               if (APR_BUCKET_IS_EOS(e))
               {
                  APR_BRIGADE_INSERT_TAIL(bbout, apr_bucket_eos_create(bbout->bucket_alloc));                                                                                           
               }

               if (!APR_BUCKET_IS_EOS(e))
               {
                  if ((rv = apr_bucket_read(e, &str, &len,APR_NONBLOCK_READ)) == APR_SUCCESS)
                  {
                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "BUCKET DATA= %s", str); 
                  }   
                  apr_bucket_copy(e,&b);
                  APR_BRIGADE_INSERT_TAIL(bbout, b);                                                                                             
               }
            }   
         
            apreq_parser_run(psr,formd,bbin);
            
            
            if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bbin)))
            {   
               ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "coucoucouc ");
               ap_remove_input_filter(f);
               break;
            }
         }
         //apr_brigade_cleanup(bbin) ;     
         //apr_brigade_destroy(bbin) ;
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "brigade %d bucket %d ", cptBrigade, cptBucket);
         
         filed = apreq_uploads(formd,f->r->pool);                         
         uploaded_files->upload_files_names=filed;
         uploaded_files->formd=formd;
         uploaded_files->rec=f->r;                                         
         apr_table_do(iterate_uploaded_files, uploaded_files, filed, NULL);
         
         ap_remove_input_filter(f) ;
         return ap_pass_brigade(f->next, bbout);   
      }                 
   }                 
   return APR_SUCCESS ;
}


Revenir vers « Développement Apache »

Qui est en ligne ?

Utilisateurs parcourant ce forum : Aucun utilisateur inscrit et 1 invité